diff --git a/.deployment b/.deployment index a7670e85780..2b834f52abb 100644 --- a/.deployment +++ b/.deployment @@ -1,3 +1,34 @@ +; .deployment is actually an INI file and parsed by the following file +; https://raw.githubusercontent.com/projectkudu/kudu/master/Kudu.Core/Infrastructure/IniFile.cs + +; Document of deployment with custom script +; https://github.com/projectkudu/kudu/wiki/Customizing-deployments#deploying-with-custom-script + +; Document of configurable settings https://github.com/projectkudu/kudu/wiki/Configurable-settings +; Runtime settings cannot be overridden in .deployment e.g. WEBSITE_NODE_DEFAULT_VERSION +; More info https://github.com/projectkudu/kudu/wiki/Configurable-settings#runtime-settings + +# Define default node version in WEBSITE_NODE_DEFAULT_VERSION APP Setting +# Find all Node.js versions from your AppService Kudu api/diagnostics/runtime +# More info https://codesanook-reactjs-server-side-rendering.scm.azurewebsites.net/api/diagnostics/runtime + +; You can define a custom environment variable as +; CUSTOM_VARIABLE = my custom variable value +; and read in a deploy.ps1 script as +; $Env:CUSTOM_VARIABLE + +; https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_powershell_exe?view=powershell-5.1#examples [config] -command = deploy.cmd +COMMAND = PowerShell -NoProfile -NoLogo -ExecutionPolicy Unrestricted -Command "& "$(Join-Path -Path $(Get-Location) -ChildPath deploy.ps1)" 2>&1 | Write-Output" + +; Set additional environment variables +; Timeout in seconds +; Set to one hour SCM_COMMAND_IDLE_TIMEOUT = 3600 + +; Variables for MSBuild +MSBUILD_PATH = D:\Program Files (x86)\MSBuild-16.4\MSBuild\Current\Bin\MSBuild.exe +SOLUTION_PATH = src/Orchard.sln + +; For Azure deployment, we use custom MS Build at root of the project. +PROJECT_PATH = Orchard.proj diff --git a/.github/workflows/build-crowdin-translation-packages.yml b/.github/workflows/build-crowdin-translation-packages.yml new file mode 100644 index 00000000000..25e57af7338 --- /dev/null +++ b/.github/workflows/build-crowdin-translation-packages.yml @@ -0,0 +1,30 @@ +name: Build Crowdin Translation Packages + +on: + workflow_dispatch: + schedule: + - cron: "0 6 * * *" + +jobs: + build-crowdin-translation-packages: + defaults: + run: + shell: pwsh + runs-on: ubuntu-latest + + steps: + - name: Orchard CMS + uses: andrii-bodnar/crowdin-request-action@aac9a865d62b37060b0ce530db5ac5cfca02dd2c # 0.0.2 + with: + route: POST /projects/{projectId}/translations/builds + projectId: 46524 + env: + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_API_TOKEN }} + + - name: Orchard CMS Gallery + uses: andrii-bodnar/crowdin-request-action@aac9a865d62b37060b0ce530db5ac5cfca02dd2c # 0.0.2 + with: + route: POST /projects/{projectId}/translations/builds + projectId: 63766 + env: + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_API_TOKEN }} diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml new file mode 100644 index 00000000000..c8a38d39aaf --- /dev/null +++ b/.github/workflows/compile.yml @@ -0,0 +1,70 @@ +name: Compile +# Compiles the solution and runs unit tests. + +on: + workflow_dispatch: + pull_request: + push: + branches: + - dev + - 1.10.x + +jobs: + compile-dotnet: + name: Compile .NET solution + defaults: + run: + shell: pwsh + runs-on: windows-latest + steps: + - name: Clone repository + uses: actions/checkout@v4.1.1 + + - name: Restore NuGet packages + run: nuget restore src/Orchard.sln + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v2 + + - name: Compile + run: msbuild Orchard.proj /m /v:minimal /t:Compile /p:MvcBuildViews=true /p:TreatWarningsAsErrors=true -WarnAsError + + - name: Test + run: msbuild Orchard.proj /m /v:minimal /t:Test + + compile-node: + name: Compile client-side assets + defaults: + run: + shell: pwsh + runs-on: windows-latest + steps: + - name: Clone repository + uses: actions/checkout@v4.1.1 + + - name: Setup NodeJS + uses: actions/setup-node@v4.0.2 + with: + node-version: '7' + + - name: Setup NPM packages + working-directory: ./src + run: | + npm install --loglevel warn + + # Install gulp globally to be able to run the rebuild task, using the same version as in the project. + $gulpVersion = (Get-Content Package.json -Raw | ConvertFrom-Json).devDependencies.gulp + Start-Process npm -NoNewWindow -Wait -ArgumentList "install gulp@$gulpVersion -g --loglevel warn" + + - name: Rebuild client-side assets + working-directory: ./src + run: | + gulp rebuild + + git add . # To make line ending changes "disappear". + $gitStatus = (git status --porcelain) + if ($gitStatus) + { + throw ("Client-side assets are not up-to-date. Please run 'gulp rebuild' and commit the changes.`n" + + [System.String]::Join([System.Environment]::NewLine, $gitStatus)) + } diff --git a/.github/workflows/specflow.yml b/.github/workflows/specflow.yml new file mode 100644 index 00000000000..93ab66a64d0 --- /dev/null +++ b/.github/workflows/specflow.yml @@ -0,0 +1,39 @@ +name: SpecFlow tests +# Compiles the solution and runs unit tests, as well the SpecFlow tests on the main development branches. + +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * *' # Every day at midnight. + +jobs: + compile: + name: SpecFlow tests + defaults: + run: + shell: pwsh + runs-on: windows-latest + strategy: + matrix: + branch: [dev, 1.10.x] + + steps: + - name: Clone repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ matrix.branch }} + + - name: Restore NuGet packages + run: nuget restore src/Orchard.sln + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2.0.0 + + - name: Compile + run: msbuild Orchard.proj /m /v:minimal /t:Compile /p:MvcBuildViews=true /p:TreatWarningsAsErrors=true -WarnAsError + + - name: Test + run: msbuild Orchard.proj /m /v:minimal /t:Test + + - name: Spec + run: msbuild Orchard.proj /m /v:minimal /t:Spec diff --git a/.gitignore b/.gitignore index be6a64c1eea..a22dca49fda 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +**/.vs/** +src/Rebracer.xml # User-specific files *.suo @@ -190,5 +192,3 @@ src/Orchard.Azure/Orchard.Azure.CloudService/Staging/ #enable all /lib artifacts !lib/**/*.* -**/.vs/* -src/Rebracer.xml diff --git a/CREDITS.txt b/CREDITS.txt index 51194d0d68b..216e1d7123b 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -187,15 +187,15 @@ License: Apache Software Foundation License 2.0 Lucene.net ----- -Website: http://incubator.apache.org/projects/lucene.net.html +Website: https://lucenenet.apache.org/ Copyright: Copyright (c) 2009 Apache Software Foundation License: Apache Software Foundation License 2.0 -MarkdownSharp +Markdig ----- -Website: http://code.google.com/p/markdownsharp/ -Copyright: Copyright (c) 2009-2011 Jeff Atwood -License: MIT +Website: https://github.com/lunet-io/markdig +Copyright: Copyright (c) 2018-2019, Alexandre Mutel +License: BSD 2-Clause Mono Class Library ----- @@ -293,4 +293,4 @@ YUI ----- Website: http://developer.yahoo.com/yui/ Copyright: Copyright (c) 2010, Yahoo! Inc. -License: New BSD \ No newline at end of file +License: New BSD diff --git a/CalculateBindingRedirects.ps1 b/CalculateBindingRedirects.ps1 new file mode 100644 index 00000000000..45f279b3f09 --- /dev/null +++ b/CalculateBindingRedirects.ps1 @@ -0,0 +1,34 @@ +[Reflection.Assembly]::LoadWithPartialName("System.Xml") | Out-Null +[Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq") | Out-Null +[System.Xml.Linq.XNamespace]$ns1 = "urn:schemas-microsoft-com:asm.v1" + +$currentPath = (Get-Item -Path ".\").FullName +$orchardWebConfigFullPath = $currentPath+"\src\Orchard.Web\Web.Config" +[XML] $orchardWebConfig = Get-Content ($orchardWebConfigFullPath) +$configFiles = Get-ChildItem -Path ($currentPath +"\src\") -Filter web.config -Recurse -ErrorAction SilentlyContinue -Force +foreach ($configFile in $configFiles) { + $configFullPath = $configFile.FullName + Write-Host "Processing $configFullPath ..." + + if ($configFullPath.ToLower().EndsWith("\orchard.web\web.config")) { #skip orchard.web config files + continue + } + [XML] $projectWebConfig = Get-Content ($configFullPath) + $elements = $projectWebConfig.configuration.runtime.assemblyBinding.dependentAssembly + foreach ($element in $elements){ + Write-Host "Checking" $element.assemblyIdentity.name + $hasBinding = $orchardWebConfig.configuration.runtime.assemblyBinding.dependentAssembly.assemblyIdentity.Where({ $_.name -eq $element.assemblyIdentity.name -and $_.publicKeyToken -eq $element.assemblyIdentity.publicKeyToken -and $_.culture -eq $element.assemblyIdentity.culture }, 'First').Count -gt 0 + if (-not $hasBinding){ + # add the node in $webConfig + Write-Host "Adding" $element.assemblyIdentity.name + $newNode = $orchardWebConfig.ImportNode($element, $true); + $orchardWebConfig.configuration.runtime.assemblyBinding.AppendChild($newNode) + Write-Host "Added " $element.assemblyIdentity.name + } else { + Write-Host "Skipped" $element.assemblyIdentity.name + } + } + Write-Host "Processed $configFullPath ..." +} + +$orchardWebConfig.Save($orchardWebConfigFullPath) diff --git a/ClickToBuild.cmd b/ClickToBuild.cmd index 8c5a5183402..920481b6971 100644 --- a/ClickToBuild.cmd +++ b/ClickToBuild.cmd @@ -1,31 +1,18 @@ -FOR %%b in ( - "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" - "%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - "%ProgramFiles%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" - - "%VS120COMNTOOLS%..\..\VC\vcvarsall.bat" - "%ProgramFiles(x86)%\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" - "%ProgramFiles%\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" - - "%VS110COMNTOOLS%..\..\VC\vcvarsall.bat" - "%ProgramFiles(x86)%\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" - "%ProgramFiles%\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" - ) do ( - if exist %%b ( - call %%b x86 - goto build - ) -) - -FOR %%b in ( - "%VS140COMNTOOLS%\vsvars32.bat" - "%VS120COMNTOOLS%\vsvars32.bat" - "%VS110COMNTOOLS%\vsvars32.bat" - ) do ( - if exist %%b ( - call %%b - goto build - ) +@echo off + +REM Necessary for the InstallDir variable to work inside the MsBuild-finding loop below. +SETLOCAL ENABLEDELAYEDEXPANSION + +for /f "usebackq tokens=1* delims=: " %%i in (`lib\vswhere\vswhere -latest -version "[16.0,18.0)" -requires Microsoft.Component.MSBuild`) do ( + if /i "%%i"=="installationPath" ( + set InstallDir=%%j + echo !InstallDir! + if exist "!InstallDir!\MSBuild\Current\Bin\MSBuild.exe" ( + echo "Using MSBuild from !InstallDir!" + set msbuild="!InstallDir!\MSBuild\Current\Bin\MSBuild.exe" + goto build + ) + ) ) echo "Unable to detect suitable environment. Build may not succeed." @@ -42,6 +29,8 @@ IF "%solution%" == "" SET solution=src\Orchard.sln lib\nuget\nuget.exe restore %solution% -msbuild /t:%target% %project% /p:Solution=%solution% /m +%msbuild% /t:%target% %project% /p:Solution=%solution% /m + +:end pause \ No newline at end of file diff --git a/DeploymentUtility.psm1 b/DeploymentUtility.psm1 new file mode 100644 index 00000000000..01dd0678074 --- /dev/null +++ b/DeploymentUtility.psm1 @@ -0,0 +1,83 @@ +Set-StrictMode -Version Latest + +# Continue a build process even though there is a warning wrote to std err. +# We will check exit code in Invoke-ExternalCommand to design whether it fail or not +$ErrorActionPreference = "Continue" + +function Add-NpmToPathVariable { + $path = "$env:Appdata\npm" + $escapedPath = [Regex]::Escape($path) + + # Remove existing npm path safe to add npm path again + $paths = $env:Path -split ';' | Where-Object { + $_ -notmatch "^$escapedPath\\?$" + } + + # Update a path variable to this session + $env:Path = ($paths + $path) -join ";" # array + element item +} + +function Invoke-ExternalCommand { + param ( + [Parameter(Mandatory = $true)] [scriptblock] $ScriptBlock + ) + + # Displays an error message and continue executing if there is a standard error. + # This is because there are some external command tools write warning message to standard error. + # Use Write-Output also fix "Window title cannot be longer than 1023 characters" issue + # https://github.com/projectkudu/kudu/issues/2635 + & $ScriptBlock 2>&1 | Write-Output + + # If last exit code is not 0, throw an exception to stop a script + if ($LastExitCode) { + throw "Failed with exit code = $LastExitCode and command = $($ScriptBlock.ToString())" + } +} + +function Write-EnviromentValue { + param ( + [Parameter(Mandatory = $true)] [String[]] $EnvironmentName + ) + + "----------------- Begin of environment variables ---------------------------------" + Get-Item -Path Env:* | Where-Object { + $EnvironmentName -contains $_.Name + } | Format-Table Name, Value -Wrap + + "----------------- End of environment variables ---------------------------------" +} + +function Install-Yarn { + "Verify if yarn installed" + if (Get-Command -Name yarn -ErrorAction Ignore) { + "Updating yarn as a global tool to the latest version" + # https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/cmd#parameters + # issue https://github.com/projectkudu/kudu/issues/2635 + Invoke-ExternalCommand -ScriptBlock { npm update yarn -g } + } + else { + "Installing yarn as a global tool" + Invoke-ExternalCommand -ScriptBlock { npm install yarn -g } + Add-NpmToPathVariable + } +} + +function Install-KuduSync { + "Verify if kudusync installed" + if (Get-Command -Name kudusync -ErrorAction Ignore) { + "Updating kudusync as a global tool to the latest version" + # https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/cmd#parameters + # issue https://github.com/projectkudu/kudu/issues/2635 + Invoke-ExternalCommand -ScriptBlock { npm update kudusync -g } + } + else { + "Installing kudusync as a global tool" + Invoke-ExternalCommand -ScriptBlock { npm install kudusync -g } + Add-NpmToPathVariable + } +} + +Export-ModuleMember -Function Invoke-ExternalCommand +Export-ModuleMember -Function Write-EnviromentValue +Export-ModuleMember -Function Install-Yarn +Export-ModuleMember -Function Install-KuduSync diff --git a/Orchard.proj b/Orchard.proj index 25004a059f7..0f5cfbc8022 100644 --- a/Orchard.proj +++ b/Orchard.proj @@ -13,9 +13,10 @@ $(ArtifactsFolder)\Source $(ArtifactsFolder)\MsDeploy $(ArtifactsFolder)\Gallery - $(MSBuildProjectDirectory)\src\Orchard.Web\Modules - $(MSBuildProjectDirectory)\src\Orchard.Web\Core - $(MSBuildProjectDirectory)\src\Orchard.Web\Themes + $(SrcFolder)\Orchard.Web + $(OrchardWebFolder)\Modules + $(OrchardWebFolder)\Core + $(OrchardWebFolder)\Themes $(BuildFolder)\Compile $(CompileFolder)\_PublishedWebsites @@ -112,15 +113,25 @@ + + + + + + + Targets="Build" + Properties="Configuration=$(Configuration);MvcBuildViews=$(MvcBuildViews)" /> @@ -150,12 +161,13 @@ - - - + + + - + + @@ -367,11 +379,6 @@ - - - @@ -379,7 +386,7 @@ - + diff --git a/README.md b/README.md index 45d5536883d..5a7073d2530 100644 --- a/README.md +++ b/README.md @@ -10,47 +10,43 @@ You can try it for free on [DotNest.com](https://dotnest.com) or on Microsoft Az ## About The Orchard Project -#### Please visit our website at http://orchardproject.net for the most current information about this project. +#### Please visit our website at https://orchardproject.net for the most current information about this project. Orchard is a free, open source, community-focused **Content Management System** built on the ASP.NET MVC platform. Orchard is built on a modern architecture that puts extensibility up-front, as its number one concern. All components in Orchard can be replaced or extended. Content is built from easily composable building blocks. Modules extend the system in a very decoupled fashion, where a commenting module for example can as easily apply to pages, blog posts, photos or products. A rich UI composition system completes the picture and ensures that you can get the exact presentation that you need for your content. -Orchard is delivered under the [.NET Foundation](https://dotnetfoundation.org/orchard-cms). It is licensed under a [New BSD license](http://www.opensource.org/licenses/bsd-license.php), which is approved by the OSI. +Orchard is delivered under the [.NET Foundation](https://www.dotnetfoundation.org/projects?searchquery=Orchard&type=project). It is licensed under a [New BSD license](https://www.opensource.org/licenses/bsd-license.php), which is approved by the OSI. Our mission is to empower our users and foster a dedicated and diverse community that builds the CMS that we all want to use. ## Project Status -Orchard is currently in version **[1.10.1](https://github.com/OrchardCMS/Orchard/releases/tag/1.10.1)**: It contains bugfixes and the more impactful changes and new features added in the latest major version (*1.10*). +Orchard is currently in version **[1.10.3](https://github.com/OrchardCMS/Orchard/releases/tag/1.10.3)**: It contains bugfixes and the more impactful changes and new features added in the latest major version (*1.10*). We invite participation by the developer community in shaping the project’s direction, so that we can publicly validate our designs and development approach. -All our releases are available on our [Releases](https://github.com/OrchardCMS/Orchard/releases) page, and it's easy to [Install Orchard using the Web Platform Installer](http://docs.orchardproject.net/Documentation/Installing-Orchard) as well. We encourage interested developers to check out the source code on the Orchard GitHub site and get involved with the project. +All our releases are available on our [Releases](https://github.com/OrchardCMS/Orchard/releases) page, and we encourage interested developers to check out the source code on the Orchard GitHub site and get involved with the project. * [Download the latest release](https://github.com/OrchardCMS/Orchard/releases) -* [Feature roadmap](http://docs.orchardproject.net/Documentation/Feature-roadmap) -* [Docs and designs/specs](http://www.orchardproject.net/docs) -* [About us](http://www.orchardproject.net/about) -* [Contact us](mailto:ofeedbk@microsoft.com) +* [Feature roadmap](https://docs.orchardproject.net/en/latest/Documentation/Feature-roadmap/) +* [Docs and designs/specs](https://docs.orchardproject.net) ## How To Get Involved We hope that by engaging with the community we will continue to shape Orchard into a valuable set of tools and applications. The Orchard team is committed to open community participation and accepts code contributions. We encourage community participation at all levels from general project feedback to bug fixes and patches. -There are many ways you can [contribute to Orchard](http://orchardproject.net/contribution): +There are many ways you can contribute to Orchard: * [Check out the code](https://github.com/OrchardCMS/Orchard) * [Write documentation](https://github.com/OrchardCMS/OrchardDoc) * [Find and file a bug](https://github.com/OrchardCMS/Orchard/issues) -* [Propose a feature idea](http://orchard.uservoice.com) -* [Ask and answer questions in our forums](http://www.orchardproject.net/discussions) and [on Stack Overflow](http://stackoverflow.com/questions/tagged/orchardcms) +* [Propose a feature idea](https://github.com/OrchardCMS/Orchard/issues/new) +* [Ask and answer questions on Stack Overflow](https://stackoverflow.com/questions/tagged/orchardcms) * [Participate in our gitter.im chatroom](https://gitter.im/OrchardCMS/Orchard) -* [Participate in forum discussions](http://orchard.codeplex.com/discussions) -* [Submit a pull request](http://docs.orchardproject.net/Documentation/Contributing-patches) -* [Translate Orchard](http://orchardproject.net/localization) -* [Contribute modules and themes to our gallery](http://gallery.orchardproject.net/) -* [Send us feedback](mailto:ofeedbk@microsoft.com) +* [Submit a pull request](https://docs.orchardproject.net/en/latest/Documentation/Contributing-patches/) +* [Translate Orchard](https://crowdin.com/project/orchard-cms) +* [Contribute modules and themes to our gallery](https://gallery.orchardproject.net/) -## The Future Of Orchard CMS: Orchard 2 +## The Future Of Orchard CMS: Orchard Core -As the underlying frameworks (.NET, ASP.NET and ASP.NET MVC) are constantly evolving, Orchard of course keeps track of the changes and improvements of these: Orchard 2 is the next generation of Orchard releases that is based on [ASP.NET Core](http://www.asp.net/core). Just like the current Orchard project, it's fully [open-source and is publicly available on GitHub](https://github.com/OrchardCMS/Orchard2). Orchard 2 (as a framework) is being built from scratch: it's still in development and does not share any of its code base (at least directly) with the current versions of Orchard. +As the underlying frameworks (.NET, ASP.NET and ASP.NET MVC) are constantly evolving, Orchard of course keeps track of the changes and improvements of these: Orchard Core is the next generation of Orchard releases that is based on [ASP.NET Core](https://www.asp.net/core). Just like the current Orchard project, it's fully [open-source and is publicly available on GitHub](https://github.com/OrchardCMS/OrchardCore). Orchard Core (as a framework) is being built from scratch: it's still in development and does not share any of its code base (at least directly) with the current versions (1.x) of Orchard. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..b7346a79dbb --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,21 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 1.0 | :x: | +| 1.1 | :x: | +| 1.2 | :x: | +| 1.3 | :x: | +| 1.4 | :x: | +| 1.5 | :x: | +| 1.6 | :x: | +| 1.7 | :x: | +| 1.8 | :x: | +| 1.9 | :x: | +| 1.10 | :white_check_mark: | + +## Reporting a Vulnerability + +Send an email to sebros@microsoft.com diff --git a/deploy.ps1 b/deploy.ps1 new file mode 100644 index 00000000000..151861049e6 --- /dev/null +++ b/deploy.ps1 @@ -0,0 +1,119 @@ +# https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/set-strictmode?view=powershell-7 +Set-StrictMode -Version Latest + +# https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-7#erroractionpreference +$ErrorActionPreference = "Continue" # Just explicit set it + +Import-Module -Name ./DeploymentUtility -Force + +"Verify if Node.js installed" +if (-not (Get-Command -Name node -ErrorAction Ignore)) { + throw ( + "Missing Node.js executable, please install Node.js." + + "If already installed, make sure it can be reached from the current environment." + ) +} + +$ARTIFACTS = "$PSScriptRoot/../artifacts" +# Set deployment source folder +if (-not $Env:DEPLOYMENT_SOURCE) { + 'Set $DEPLOYMENT_SOURCE variable from the current directory' + $Env:DEPLOYMENT_SOURCE = $PSScriptRoot +} + +if (-not $Env:DEPLOYMENT_TARGET) { + 'Set $DEPLOYMENT_TARGET variable' + $Env:DEPLOYMENT_TARGET = "$ARTIFACTS/wwwroot" +} + +if (-not $Env:NEXT_MANIFEST_PATH) { + 'Set $NEXT_MANIFEST_PATH variable' + $Env:NEXT_MANIFEST_PATH = "$ARTIFACTS/manifest" + + if (-not $Env:PREVIOUS_MANIFEST_PATH) { + 'Set $PREVIOUS_MANIFEST_PATH variable' + $Env:PREVIOUS_MANIFEST_PATH = "$ARTIFACTS/manifest" + } +} + +# Log environment variables +$environmentNameToWriteValue = @( + "DEPLOYMENT_SOURCE" + "DEPLOYMENT_TARGET" + "NEXT_MANIFEST_PATH" + "PREVIOUS_MANIFEST_PATH" + "WEBSITE_NODE_DEFAULT_VERSION" + "WEBSITE_NPM_DEFAULT_VERSION" + "SCM_REPOSITORY_PATH" + "SOLUTION_PATH" + "PROJECT_PATH" + "MSBUILD_PATH" + "Path" +) +Write-EnviromentValue -EnvironmentName $environmentNameToWriteValue + +################ Build Node.js project with yarn if there is yarn.lock file ################ +$nodeProjectsDir = Get-ChildItem -Path . -Recurse -Filter "yarn.lock" | + Select-Object -ExpandProperty DirectoryName -Unique | + Where-Object { $_ -NotMatch "node_modules" } + +"Node projects directory:" +$nodeProjectsDir + +Install-Yarn + +$nodeProjectsDir | Foreach-Object { + $projectDir = $_ + Push-Location -Path $projectDir + + "Current Node project directory is $(Get-Location)" + "Installing npm packages with yarn" + Invoke-ExternalCommand -ScriptBlock { yarn install } + + "Building Node.js project with yarn" + Invoke-ExternalCommand -ScriptBlock { yarn build } + Pop-Location +} +########################################################################################### + +# Build .NET project +"Restore NuGet packages" +# REF https://docs.microsoft.com/en-us/nuget/reference/cli-reference/cli-ref-restore#options +$msBuildDir = Split-Path -Path $Env:MSBUILD_PATH -Parent +Invoke-ExternalCommand -ScriptBlock { ./lib/nuget/nuget.exe restore "$Env:SOLUTION_PATH" -MSBuildPath "$msBuildDir" } + +"Build .NET project to the pre-compiled directory" +$preCompiledDir = "$Env:DEPLOYMENT_SOURCE/build/Precompiled" + +"Build .NET project to the temp directory" +"Building the project with MSBuild to '$preCompiledDir'" +Invoke-ExternalCommand -ScriptBlock { + cmd /c "$Env:MSBUILD_PATH" ` + "$Env:PROJECT_PATH" ` + /t:Precompiled ` + /p:PreCompiledDir=$preCompiledDir ` + /verbosity:minimal ` + /maxcpucount ` + /nologo ` + $Env:SCM_BUILD_ARGS + # Set SCM_BUILD_ARGS as App Service Configuration to any string you want to append to the MSBuild command line. +} + +Install-KuduSync + +"Syncing a build output to a deployment folder" +Invoke-ExternalCommand -ScriptBlock { + cmd /c kudusync ` + -f "$preCompiledDir" ` + -t "$Env:DEPLOYMENT_TARGET" ` + -n "$Env:NEXT_MANIFEST_PATH" ` + -p "$Env:PREVIOUS_MANIFEST_PATH" ` + -i ".git;.hg;.deployment;deploy.cmd;deploy.ps1;node_modules;" +} + +if ($Env:POST_DEPLOYMENT_ACTION) { + "Post deployment stub" + Invoke-ExternalCommand -ScriptBlock { $Env:POST_DEPLOYMENT_ACTION } +} + +"Deployment successfully" diff --git a/lib/nhibernate.linq/NHibernate.Linq.dll b/lib/nhibernate.linq/NHibernate.Linq.dll deleted file mode 100644 index 4d4152a4f8a..00000000000 Binary files a/lib/nhibernate.linq/NHibernate.Linq.dll and /dev/null differ diff --git a/lib/nhibernate.linq/orchard-customizations.txt b/lib/nhibernate.linq/orchard-customizations.txt deleted file mode 100644 index ddb2b34c77d..00000000000 --- a/lib/nhibernate.linq/orchard-customizations.txt +++ /dev/null @@ -1,4 +0,0 @@ -This library has been modified to be compatible with NH 3.3. -The file DetachedCriteriaAdapter.cs in this folder is used instead of the original onw from soure code. - -Source code can be found at http://sourceforge.net/projects/nhcontrib/files/NHibernate.Linq/1.0/NHibernate.Linq-1.0.0.GA-src.zip diff --git a/lib/nuget/nuget.exe b/lib/nuget/nuget.exe index 9f8781de0db..a6caf01c9e3 100644 Binary files a/lib/nuget/nuget.exe and b/lib/nuget/nuget.exe differ diff --git a/lib/vswhere/vswhere.exe b/lib/vswhere/vswhere.exe new file mode 100644 index 00000000000..80706d852e5 Binary files /dev/null and b/lib/vswhere/vswhere.exe differ diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 00000000000..0a382f05cc7 --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +end_of_line = crlf +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.cs] +csharp_new_line_before_open_brace = none +dotnet_sort_system_directives_first = true \ No newline at end of file diff --git a/src/Gulpfile.js b/src/Gulpfile.js index d9554f622b8..77b4df2615b 100644 --- a/src/Gulpfile.js +++ b/src/Gulpfile.js @@ -97,7 +97,13 @@ function resolveAssetGroupPaths(assetGroup, assetManifestPath) { assetGroup.manifestPath = assetManifestPath; assetGroup.basePath = path.dirname(assetManifestPath); assetGroup.inputPaths = assetGroup.inputs.map(function (inputPath) { - return path.resolve(path.join(assetGroup.basePath, inputPath)); + var excludeFile = false; + if (inputPath.startsWith('!')) { + inputPath = inputPath.slice(1); + excludeFile = true; + } + var newPath = path.resolve(path.join(assetGroup.basePath, inputPath)); + return (excludeFile ? '!' : '') + newPath; }); assetGroup.watchPaths = []; if (assetGroup.watch) { @@ -216,7 +222,7 @@ function buildJsPipeline(assetGroup, doConcat, doRebuild) { // Source maps are useless if neither concatenating nor transpiling. if ((!doConcat || assetGroup.inputPaths.length < 2) && !assetGroup.inputPaths.some(function (inputPath) { return path.extname(inputPath).toLowerCase() === ".ts"; })) generateSourceMaps = false; - var typeScriptOptions = { allowJs: true, noImplicitAny: true, noEmitOnError: true }; + var typeScriptOptions = { allowJs: true, noImplicitAny: true, noEmitOnError: true, module: 'amd' }; if (assetGroup.typeScriptOptions) typeScriptOptions = Object.assign(typeScriptOptions, assetGroup.typeScriptOptions); // Merge override options from asset group if any. if (doConcat) diff --git a/src/Libraries/NHibernate/NHibernate.Linq/AssemblyInfo.cs b/src/Libraries/NHibernate/NHibernate.Linq/AssemblyInfo.cs new file mode 100644 index 00000000000..ee7696278a1 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Security; + +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.4016 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +[assembly: CLSCompliantAttribute(true)] +[assembly: AssemblyTitleAttribute("NHibernate.Linq")] +[assembly: AssemblyDescriptionAttribute("A linq provider for NHibernate")] +[assembly: AssemblyCompanyAttribute("NHForge.org")] +[assembly: AssemblyProductAttribute("NHibernate.Linq")] +[assembly: AssemblyCopyrightAttribute("Licensed under LGPL.")] +[assembly: AssemblyVersionAttribute("1.0.0.4000")] +[assembly: AssemblyInformationalVersionAttribute("1.0.0.4000")] +[assembly: AssemblyFileVersionAttribute("1.0.0.4000")] +[assembly: AssemblyDelaySignAttribute(false)] +[assembly: AllowPartiallyTrustedCallersAttribute()] + diff --git a/src/Libraries/NHibernate/NHibernate.Linq/CriteriaResultReader.cs b/src/Libraries/NHibernate/NHibernate.Linq/CriteriaResultReader.cs new file mode 100644 index 00000000000..8337d2c1c20 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/CriteriaResultReader.cs @@ -0,0 +1,35 @@ +using System.Collections; +using System.Collections.Generic; + +namespace NHibernate.Linq +{ + /// + /// Wraps an ICriteria object providing results when necessary. + /// + /// + public class CriteriaResultReader : IEnumerable, IEnumerable + { + private readonly ICriteria _criteria; + + public CriteriaResultReader(ICriteria criteria) + { + _criteria = criteria; + } + + private IList List() + { + return _criteria.List(); + } + + public IEnumerator GetEnumerator() + { + foreach (var item in List()) + yield return (T)item; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return List().GetEnumerator(); + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Expressions/CollectionAccessExpression.cs b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/CollectionAccessExpression.cs new file mode 100644 index 00000000000..ffa1e85b1fd --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/CollectionAccessExpression.cs @@ -0,0 +1,21 @@ +using NHibernate.Type; + +namespace NHibernate.Linq.Expressions +{ + public class CollectionAccessExpression : PropertyAccessExpression + { + private readonly EntityExpression _elementExpression; + + public EntityExpression ElementExpression + { + get { return _elementExpression; } + } + + public CollectionAccessExpression(string name, System.Type type, IType nhibernateType, + EntityExpression expression, EntityExpression elementExpression) + : base(name, type, nhibernateType, expression, NHibernateExpressionType.CollectionAccess) + { + _elementExpression = elementExpression; + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Expressions/EntityExpression.cs b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/EntityExpression.cs new file mode 100644 index 00000000000..75d4fa00cd3 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/EntityExpression.cs @@ -0,0 +1,63 @@ +using System.Linq.Expressions; +using NHibernate.Metadata; + +namespace NHibernate.Linq.Expressions +{ + public class EntityExpression : NHibernateExpression + { + private readonly string _alias; + private readonly string _associationPath; + private readonly IClassMetadata _metaData; + private readonly Expression _expression; + + public string Alias + { + get { return _alias; } + } + + public string AssociationPath + { + get { return _associationPath; } + } + + public IClassMetadata MetaData + { + get { return _metaData; } + } + + public Expression Expression + { + get { return _expression; } + } + + public EntityExpression(string associationPath, string alias, System.Type type, IClassMetadata metaData, Expression expression) + : base(IsRoot(expression) ? NHibernateExpressionType.RootEntity : NHibernateExpressionType.Entity, type) + { + _associationPath = associationPath; + _alias = alias; + _metaData = metaData; + _expression = expression; + } + + private static bool IsRoot(Expression expr) + { + if (expr == null) return true; + if (!(expr is EntityExpression)) return true; + return false; + } + + public override string ToString() + { + return Alias; + } + + public virtual string GetAliasedIdentifierPropertyName() + { + if ((NHibernateExpressionType)this.NodeType == NHibernateExpressionType.RootEntity) + { + return this.MetaData.IdentifierPropertyName; + } + return string.Format("{0}.{1}", this.Alias, this.MetaData.IdentifierPropertyName); + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Expressions/NHibernateExpression.cs b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/NHibernateExpression.cs new file mode 100644 index 00000000000..ca9676e9498 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/NHibernateExpression.cs @@ -0,0 +1,21 @@ +using System; +using System.Linq.Expressions; + +namespace NHibernate.Linq.Expressions +{ + public abstract class NHibernateExpression : Expression + { + + public NHibernateExpression(NHibernateExpressionType nodeType, System.Type type) + : base() { + + _nodeType = nodeType; + _type = type; + } + + private readonly NHibernateExpressionType _nodeType; + public override ExpressionType NodeType { get { return (ExpressionType)_nodeType; } } + private readonly System.Type _type; + public override System.Type Type { get { return _type; } } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Expressions/NHibernateExpressionType.cs b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/NHibernateExpressionType.cs new file mode 100644 index 00000000000..9213efc85a3 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/NHibernateExpressionType.cs @@ -0,0 +1,15 @@ + +namespace NHibernate.Linq.Expressions +{ + /// + /// Extended node types for custom expressions + /// + public enum NHibernateExpressionType + { + QuerySource = 1000, //make sure these don't overlap with ExpressionType + RootEntity, + Entity, + PropertyAccess, + CollectionAccess + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Expressions/PropertyAccessExpression.cs b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/PropertyAccessExpression.cs new file mode 100644 index 00000000000..257c3d1e426 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/PropertyAccessExpression.cs @@ -0,0 +1,48 @@ +using System; +using NHibernate.Type; + +namespace NHibernate.Linq.Expressions +{ + public class PropertyAccessExpression : NHibernateExpression + { + private readonly string _name; + private readonly EntityExpression _expression; + private readonly IType _nhibernateType; + + public string Name + { + get { return _name; } + } + + public EntityExpression Expression + { + get { return _expression; } + } + + public IType NHibernateType + { + get { return _nhibernateType; } + } + + public PropertyAccessExpression(string name, System.Type type, IType nhibernateType, EntityExpression expression) + : this(name, type, nhibernateType, expression, NHibernateExpressionType.PropertyAccess) { } + + protected PropertyAccessExpression(string name, System.Type type, IType nhibernateType, EntityExpression expression, NHibernateExpressionType nodeType) + : base(nodeType, type) + { + if (String.IsNullOrEmpty(name)) throw new ArgumentNullException("name"); + if (type == null) throw new ArgumentNullException("type"); + if (nhibernateType == null) throw new ArgumentNullException("nhibernateType"); + if (expression == null) throw new ArgumentNullException("expression"); + + _name = name; + _expression = expression; + _nhibernateType = nhibernateType; + } + + public override string ToString() + { + return this.Expression.ToString() + "." + this.Name; + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Expressions/QuerySourceExpression.cs b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/QuerySourceExpression.cs new file mode 100644 index 00000000000..1f4f8b093ca --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/QuerySourceExpression.cs @@ -0,0 +1,46 @@ +using System; +using System.Linq; + +namespace NHibernate.Linq.Expressions +{ + public class QuerySourceExpression : NHibernateExpression + { + private readonly string _alias; + private readonly IQueryable _query; + private readonly System.Type _elementType; + + public string Alias + { + get { return _alias; } + } + + public IQueryable Query + { + get { return _query; } + } + + public System.Type ElementType + { + get { return _elementType ?? Query.ElementType; } + } + + public QuerySourceExpression(string alias, IQueryable query) + : this(alias, query, null) { } + + public QuerySourceExpression(string alias, IQueryable query, System.Type elementType) + : base(NHibernateExpressionType.QuerySource, query.GetType()) + { + _alias = alias; + _query = query; + _elementType = elementType; + } + + public override string ToString() + { + if (!String.IsNullOrEmpty(Alias)) + return Alias; + + return base.ToString(); + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Expressions/SqlAggregateFunctionProjection.cs b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/SqlAggregateFunctionProjection.cs new file mode 100644 index 00000000000..7945c86c4de --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/SqlAggregateFunctionProjection.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using NHibernate.Criterion; +using NHibernate.Linq.Util; +using NHibernate.SqlCommand; +using NHibernate.Type; + +namespace NHibernate.Linq.Expressions +{ + public class SqlAggregateFunctionProjection : AggregateProjection + { + public SqlAggregateFunctionProjection(string functionName, string propertyName) + : this(functionName, propertyName, null) + { + } + + public SqlAggregateFunctionProjection(string functionName, string propertyName, System.Type returnType) + : this(functionName, propertyName, returnType, null) + { + } + + public SqlAggregateFunctionProjection(string functionName, string propertyName, System.Type returnType, object[] paramValues) + : this(functionName, propertyName, 0, returnType, paramValues) + { + } + + public SqlAggregateFunctionProjection(string functionName, string propertyName, int propertyPosition, System.Type returnType, + object[] paramValues) + : base(functionName, propertyName) + { + ReturnType = returnType; + ParameterValues = paramValues; + PropertyPosition = propertyPosition; + } + + public System.Type ReturnType { get; private set; } + public Object[] ParameterValues { get; private set; } + public int PropertyPosition { get; private set; } + + public override IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery) + { + if (ReturnType != null) + { + return new[] { TypeFactory.HeuristicType(ReturnType.Name) }; + } + + return base.GetTypes(criteria, criteriaQuery); + } + + public override SqlString ToSqlString(ICriteria criteria, int loc, ICriteriaQuery criteriaQuery) + { + if (ParameterValues != null && ParameterValues.Length > 0) + { + var sql = new SqlStringBuilder(); + sql.Add(aggregate).Add("("); + bool hasProperty = false; + bool hasParameter = false; + + for (int i = 0; i < ParameterValues.Length; i++) + { + if (PropertyPosition == i) + { + if (i > 0) sql.Add(", "); + sql.Add(criteriaQuery.GetColumn(criteria, propertyName)).Add(", "); + hasProperty = true; + } + else if (i > 0) + { + sql.Add(", "); + } + + sql.Add(LinqUtil.SqlEncode(ParameterValues[i])); + hasParameter = true; + } + if (!hasProperty) + { + if (hasParameter) sql.Add(", "); + sql.Add(criteriaQuery.GetColumn(criteria, propertyName)); + } + + return sql.Add(") as y").Add(loc.ToString()).Add("_").ToSqlString(); + } + + // if ParameterValues were not specified, we defer to the base functionality + return base.ToSqlString(criteria, loc, criteriaQuery); + } + } +} \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Expressions/SqlFunctionAttribute.cs b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/SqlFunctionAttribute.cs new file mode 100644 index 00000000000..a51a60d9810 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/SqlFunctionAttribute.cs @@ -0,0 +1,37 @@ +using System; + +namespace NHibernate.Linq.Expressions +{ + /// + /// Associates a method with a corresponding SQL function. + /// + [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] + public class SqlFunctionAttribute : Attribute + { + /// + /// Initializes a new instance of the class. + /// + public SqlFunctionAttribute() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The name of the schema that owns the SQL function. + public SqlFunctionAttribute(string owner) + { + Owner = owner; + } + + /// + /// Gets or sets the name of the schema that owns the SQL function. + /// + public string Owner { get; set; } + + /// + /// Gets or sets the position of the function parameter that accepts the property name. + /// + public int PropertyPosition { get; set; } + } +} \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Expressions/SqlFunctionExpression.cs b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/SqlFunctionExpression.cs new file mode 100644 index 00000000000..fcc53c9efbf --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Expressions/SqlFunctionExpression.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using NHibernate.Criterion; +using NHibernate.Engine; +using NHibernate.SqlCommand; +using NHibernate.Type; + +namespace NHibernate.Linq.Expressions +{ + public class SqlFunctionExpression : ICriterion + { + private String op; + + public SqlFunctionExpression(String functionName, System.Type returnType, ICriterion innerCriterion) + : this(functionName, returnType, null, null, innerCriterion, 0, null) + { + } + + public SqlFunctionExpression(String functionName, System.Type returnType, Object[] paramValues, + System.Type[] paramTypes, ICriterion innerCriterion) + : this(functionName, returnType, paramValues, paramTypes, innerCriterion, 0, null) + { + } + + public SqlFunctionExpression(String functionName, System.Type returnType, Object[] paramValues, + System.Type[] paramTypes, ICriterion innerCriterion, int propertyPosition) + : this(functionName, returnType, paramValues, paramTypes, innerCriterion, propertyPosition, null) + { + } + + public SqlFunctionExpression(String functionName, System.Type returnType, Object[] paramValues, + System.Type[] paramTypes, ICriterion innerCriterion, int propertyPosition, + SqlFunctionExpression rightFunction) + { + FunctionName = functionName; + ReturnType = returnType; + ParameterValues = paramValues; + ParameterTypes = paramTypes; + InnerCriterion = innerCriterion; + PropertyPosition = propertyPosition; + RightFunction = rightFunction; + } + + private SqlFunctionExpression RightFunction { get; set; } + public ICriterion InnerCriterion { get; set; } + public String FunctionName { get; private set; } + public System.Type ReturnType { get; private set; } + public Object[] ParameterValues { get; private set; } + public System.Type[] ParameterTypes { get; private set; } + public int PropertyPosition { get; private set; } + + protected virtual string Op + { + get + { + if (String.IsNullOrEmpty(op)) + { + op = InnerCriterion.GetType().GetProperty("Op", BindingFlags.NonPublic | BindingFlags.Instance) + .GetValue(InnerCriterion, null) as String; + } + + return op; + } + } + + #region ICriterion Members + + public virtual TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery) + { + var values = new List(); + if (ParameterValues != null) + { + for (int i = 0; i < ParameterValues.Length; i++) + { + values.Add(new TypedValue(TypeFactory.HeuristicType(ParameterTypes[i].Name), ParameterValues[i])); + } + } + if (ReturnType != null && InnerCriterion is SimpleExpression) + { + var simple = InnerCriterion as SimpleExpression; + values.Add(new TypedValue(TypeFactory.HeuristicType(ReturnType.Name), simple.Value)); + } + if (RightFunction != null) + { + values.AddRange(RightFunction.GetTypedValues(criteria, criteriaQuery)); + } + + return values.ToArray(); + } + + public virtual SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery) + { + var sql = new SqlStringBuilder(); + string leftPropertyName = null; + string rightPropertyName = null; + + if (InnerCriterion is SimpleExpression) + { + leftPropertyName = ((SimpleExpression)InnerCriterion).PropertyName; + } + else if (InnerCriterion is PropertyExpression) + { + System.Type type = typeof(PropertyExpression); + leftPropertyName = + type.GetField("_lhsPropertyName", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(InnerCriterion) as + String; + rightPropertyName = + type.GetField("_rhsPropertyName", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(InnerCriterion) as + String; + } + + AddParameters(leftPropertyName, sql, criteria, criteriaQuery); + sql.Add(" ").Add(Op).Add(" "); + + if (RightFunction != null) + { + RightFunction.AddParameters(rightPropertyName, sql, criteria, criteriaQuery); + } + else + { + sql.AddParameter(); + } + + return sql.ToSqlString(); + } + + public IProjection[] GetProjections() + { + return null; + } + + #endregion + + private void AddParameters(String propertyName, SqlStringBuilder sql, ICriteria criteria, ICriteriaQuery criteriaQuery) + { + bool hasProperty = false; + bool hasParameter = false; + + sql.Add(FunctionName).Add("("); + + if (ParameterValues != null && ParameterValues.Length > 0) + { + for (int i = 0; i < ParameterValues.Length; i++) + { + if (PropertyPosition == i) + { + if (i > 0) sql.Add(", "); + sql.Add(criteriaQuery.GetColumn(criteria, propertyName)).Add(", "); + hasProperty = true; + } + else if (i > 0) + { + sql.Add(", "); + } + + sql.AddParameter(); + hasParameter = true; + } + } + if (!hasProperty) + { + if (hasParameter) sql.Add(", "); + sql.Add(criteriaQuery.GetColumn(criteria, propertyName)); + } + + sql.Add(")"); + } + } +} \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/IDbMethods.cs b/src/Libraries/NHibernate/NHibernate.Linq/IDbMethods.cs new file mode 100644 index 00000000000..a8af4d2fcff --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/IDbMethods.cs @@ -0,0 +1,9 @@ +namespace NHibernate.Linq +{ + /// + /// Marker interface used to conditionally include database provider specific methods. + /// + public interface IDbMethods + { + } +} \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/INHibernateQueryable.cs b/src/Libraries/NHibernate/NHibernate.Linq/INHibernateQueryable.cs new file mode 100644 index 00000000000..470d821bbd8 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/INHibernateQueryable.cs @@ -0,0 +1,14 @@ +using System.Linq; + +namespace NHibernate.Linq +{ + public interface INHibernateQueryable + { + QueryOptions QueryOptions { get; } + } + + public interface INHibernateQueryable : INHibernateQueryable, IOrderedQueryable + { + IQueryable Expand(string path); + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/NHibernate.Linq.build b/src/Libraries/NHibernate/NHibernate.Linq/NHibernate.Linq.build new file mode 100644 index 00000000000..7b6021d46e9 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/NHibernate.Linq.build @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/NHibernate.Linq.csproj b/src/Libraries/NHibernate/NHibernate.Linq/NHibernate.Linq.csproj new file mode 100644 index 00000000000..46467801f78 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/NHibernate.Linq.csproj @@ -0,0 +1,139 @@ + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {2CF9A83A-BC40-4485-A763-BFF59B2EBDAD} + Library + Properties + NHibernate.Linq + NHibernate.Linq + v4.8 + 512 + + + false + ..\NH.Linq.snk + + + + + 3.5 + + + + true + full + false + bin\Debug\ + DEBUG + prompt + 4 + false + + + none + true + bin\Release\ + TRACE;USING_NET_35_SP1 + prompt + 4 + false + + + + ..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll + + + ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll + + + + ..\..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll + + + ..\..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll + + + ..\..\..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll + + + + + 3.5 + + + + 3.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/NHibernateContext.cs b/src/Libraries/NHibernate/NHibernate.Linq/NHibernateContext.cs new file mode 100644 index 00000000000..51d6a4d81f4 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/NHibernateContext.cs @@ -0,0 +1,432 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data.Services; +using System.Linq; +using System.Reflection; +using NHibernate.Metadata; + +namespace NHibernate.Linq +{ + /// + /// Wraps an object to provide base functionality + /// for custom, database-specific context classes. + /// + public abstract class NHibernateContext : IDisposable, ICloneable, IUpdatable, IExpandProvider + { + /// + /// Provides access to database provider specific methods. + /// + public readonly IDbMethods Methods; + + private ISession session; + + /// + /// Initializes a new instance of the class. + /// + public NHibernateContext() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// An initialized object. + public NHibernateContext(ISession session) + { + this.session = session; + } + + /// + /// Gets a reference to the associated with this object. + /// + public virtual ISession Session + { + get + { + if (session == null) + { + // Attempt to get the Session + session = ProvideSession(); + } + return session; + } + } + + + + /// + /// Allows for empty construction but provides an interface for an interface to have the derived + /// classes provide a session object late in the cycle. + /// + /// The Required object. + protected virtual ISession ProvideSession() + { + // Should not be called as supplying the session in the constructor + throw new NotImplementedException("If NHibernateContext is constructed with the empty constructor, inheritor is required to override ProvideSession to supply Session."); + } + + #region ICloneable Members + + /// + /// Creates a new object that is a copy of the current instance. + /// + /// + public virtual object Clone() + { + if (session == null) + { + throw new ArgumentNullException("session"); + } + + return Activator.CreateInstance(GetType(), session); + } + + #endregion + + #region IDisposable Members + + /// + /// Disposes the wrapped object. + /// + public virtual void Dispose() + { + if (session != null) + { + session.Dispose(); + session = null; + } + } + + #endregion + + #region IUpdatable Members + + List _updateCache = null; + /// + /// Gets the update cache. + /// + /// The update cache. + List UpdateCache + { + get + { + if (_updateCache == null) + { + _updateCache = new List(); + } + return _updateCache; + } + } + + /// + /// Adds the reference to collection. + /// + /// The target resource. + /// Name of the property. + /// The resource to be added. + void IUpdatable.AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded) + { + IClassMetadata metadata = session.SessionFactory.GetClassMetadata(targetResource.GetType().FullName); + if (metadata == null) + { + throw new DataServiceException("Type not recognized as a valid type for this Context"); + } + + // Get the property to use to add the resource to + object collection = metadata.GetPropertyValue(targetResource, propertyName); + + // Try with IList implementation first (its faster) + if (collection is IList) + { + ((IList)collection).Add(resourceToBeAdded); + } + else // Try with Reflection's Add() + { + MethodInfo addMethod = collection.GetType().GetMethod("Add", BindingFlags.Public | BindingFlags.Instance); + if (addMethod == null) + { + throw new DataServiceException(string.Concat("Could not determine the collection type of the ", propertyName, " property.")); + } + addMethod.Invoke(collection, new object[] { resourceToBeAdded }); + } + } + + /// + /// Clears the changes. + /// + void IUpdatable.ClearChanges() + { + UpdateCache.Clear(); + session.Clear(); + } + + /// + /// Creates the resource. + /// + /// Name of the container. + /// Full name of the type. + /// Newly created Resource + object IUpdatable.CreateResource(string containerName, string fullTypeName) + { + // Get the metadata + IClassMetadata metadata = session.SessionFactory.GetClassMetadata(fullTypeName); + object newResource = metadata.Instantiate(null); + + // We can't save it to the session as it may not be valid yet + // This happens if the key is a non-initancable key (e.g. Northwind.Customers) + // So we save them to a local cache. Only when SaveAll happens will be push them to the Session + UpdateCache.Add(newResource); + + // Returns the new resource + return newResource; + } + + /// + /// Deletes the resource. + /// + /// The target resource. + void IUpdatable.DeleteResource(object targetResource) + { + // Push it to the Session to support deletion + if (UpdateCache.Contains(targetResource)) + { + UpdateCache.Remove(targetResource); + session.Save(targetResource); + } + + // Mark it as deleted + if (session.Contains(targetResource)) session.Delete(targetResource); + } + + /// + /// Gets the resource. + /// + /// The query. + /// Full name of the type. + /// + object IUpdatable.GetResource(System.Linq.IQueryable query, string fullTypeName) + { + // Get the first result + IEnumerable results = (IEnumerable)query; + object returnValue = null; + foreach (object result in results) + { + if (returnValue != null) break; + returnValue = result; + } + + // Check the Typename if needed + if (fullTypeName != null) + { + if (fullTypeName != returnValue.GetType().FullName) + { + throw new DataServiceException("Incorrect Type Returned"); + } + } + + // Return the resource + return returnValue; + } + + /// + /// Gets the value. + /// + /// The target resource. + /// Name of the property. + /// + object IUpdatable.GetValue(object targetResource, string propertyName) + { + IClassMetadata metadata = session.SessionFactory.GetClassMetadata(targetResource.GetType().FullName); + if (metadata == null) + { + throw new DataServiceException("Type not recognized as a valid type for this Context"); + } + + // If + if (metadata.IdentifierPropertyName == propertyName) + { + return metadata.GetIdentifier(targetResource); + } + else + { + return metadata.GetPropertyValue(targetResource, propertyName); + } + } + + /// + /// Removes the reference from collection. + /// + /// The target resource. + /// Name of the property. + /// The resource to be removed. + void IUpdatable.RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved) + { + IClassMetadata metadata = session.SessionFactory.GetClassMetadata(targetResource.GetType().FullName); + if (metadata == null) + { + throw new DataServiceException("Type not recognized as a valid type for this Context"); + } + + // Get the property to use to remove the resource to + object collection = metadata.GetPropertyValue(targetResource, propertyName); + + // Try with IList implementation first (its faster) + if (collection is IList) + { + ((IList)collection).Remove(resourceToBeRemoved); + } + else // Try with Reflection's Add() + { + MethodInfo removeMethod = collection.GetType().GetMethod("Remove", BindingFlags.Public | BindingFlags.Instance); + if (removeMethod == null) + { + throw new DataServiceException(string.Concat("Could not determine the collection type of the ", propertyName, " property.")); + } + removeMethod.Invoke(collection, new object[] { resourceToBeRemoved }); + } + } + + /// + /// Replaces the resource. + /// + /// The resource to reset. + /// + object IUpdatable.ResetResource(object resource) + { + IUpdatable update = this; + + // Create a new resource of the same type + // but only make a local copy as we're only using it to set the default fields + // Get the metadata + IClassMetadata metadata = session.SessionFactory.GetClassMetadata(resource.GetType().ToString()); + object tempCopy = metadata.Instantiate(null); + + // Copy the default non-keys + foreach (string propName in metadata.PropertyNames) + { + object value = metadata.GetPropertyValue(tempCopy, propName); + update.SetValue(resource, propName, value); + } + + //Return the new resource + return resource; + } + + /// + /// Resolves the resource. + /// + /// The resource. + /// + object IUpdatable.ResolveResource(object resource) + { + // Resolve Resource always just returns the resource + // since we not using tokens or cookies to the actual objects + // the resources are always the actual CLR objects + return resource; + } + + /// + /// Saves the changes. + /// + void IUpdatable.SaveChanges() + { + // All saves must be all or nothing. + using (ITransaction tx = Session.BeginTransaction()) + { + try + { + // If we have anything in the object cache, + // add it to session. + if (_updateCache != null) + { + _updateCache.ForEach(o => session.SaveOrUpdate(o)); + _updateCache.Clear(); + } + + // Push the changes to the database + session.Flush(); + + // Commit the Transaction + tx.Commit(); + } + catch (Exception ex) + { + // If anythign goes wrong, it all gets rolled back + tx.Rollback(); + + // Send the error back to the user + throw new DataServiceException("Failed to save changes. See inner exception for details", ex); + } + } + } + + /// + /// Sets the reference. + /// + /// The target resource. + /// Name of the property. + /// The property value. + void IUpdatable.SetReference(object targetResource, string propertyName, object propertyValue) + { + ((IUpdatable)this).SetValue(targetResource, propertyName, propertyValue); + } + + /// + /// Sets the value. + /// + /// The target resource. + /// Name of the property. + /// The property value. + void IUpdatable.SetValue(object targetResource, string propertyName, object propertyValue) + { + IClassMetadata metadata = session.SessionFactory.GetClassMetadata(targetResource.GetType().FullName); + if (metadata == null) + { + throw new DataServiceException("Type not recognized as a valid type for this Context"); + } + + // See if its the Key property first + if (metadata.IdentifierPropertyName == propertyName) + { + metadata.SetIdentifier(targetResource, propertyValue); + } + else // Else set the property + { + metadata.SetPropertyValue(targetResource, propertyName, propertyValue); + } + } + + #endregion + + #region IExpandProvider Members + + IEnumerable IExpandProvider.ApplyExpansions(IQueryable queryable, ICollection expandPaths) + { + if (queryable == null) throw new DataServiceException("Query cannot be null"); + + INHibernateQueryable nHibQuery = queryable as INHibernateQueryable; + if (nHibQuery == null) throw new DataServiceException("Expansion only supported on INHibernateQueryable queries"); + + if (expandPaths.Count == 0) throw new DataServiceException("Expansion Paths cannot be null"); + foreach (ExpandSegmentCollection coll in expandPaths) + { + foreach (ExpandSegment seg in coll) + { + if (seg.HasFilter) + { + throw new DataServiceException("NHibernate does not support Expansions with Filters"); + } + else + { + nHibQuery.QueryOptions.AddExpansion(seg.Name); + } + } + } + + return nHibQuery as IEnumerable; + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/NHibernateExtensions.cs b/src/Libraries/NHibernate/NHibernate.Linq/NHibernateExtensions.cs new file mode 100644 index 00000000000..04e6be2f2f3 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/NHibernateExtensions.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections; +using System.Linq; +using System.Linq.Expressions; + +namespace NHibernate.Linq +{ + /// + /// Provides a static method that enables LINQ syntax for NHibernate Criteria Queries. + /// + public static class NHibernateExtensions + { + /// + /// Creates a new object used to evaluate an expression tree. + /// + /// An NHibernate entity type. + /// An initialized object. + /// An used to evaluate an expression tree. + public static INHibernateQueryable Linq(this ISession session) + { + QueryOptions options = new QueryOptions(); + return new Query(new NHibernateQueryProvider(session, options), options); + } + + public static INHibernateQueryable Linq(this ISession session,string entityName) + { + QueryOptions options = new QueryOptions(); + return new Query(new NHibernateQueryProvider(session, options,entityName), options); + } + + public static void List(this ISession session, Expression expr, IList list) + { + var options = new QueryOptions(); + var queryProvider = new NHibernateQueryProvider(session, options); + IQueryable queryable = new Query(queryProvider, options); + queryable = queryable.Where((Expression>)expr); + + var result = queryProvider.TranslateExpression(queryable.Expression); + var criteria = result as ICriteria; + if (criteria != null) + { + criteria.List(list); + } + else + { + var items = result as IEnumerable; + if (items != null) + { + foreach (var item in items) + { + list.Add(item); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/NHibernateQueryProvider.cs b/src/Libraries/NHibernate/NHibernate.Linq/NHibernateQueryProvider.cs new file mode 100644 index 00000000000..b276f3077ac --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/NHibernateQueryProvider.cs @@ -0,0 +1,62 @@ +using System; +using System.Linq.Expressions; +using NHibernate.Engine; +using NHibernate.Linq.Util; +using NHibernate.Linq.Visitors; + +namespace NHibernate.Linq +{ + public class NHibernateQueryProvider : QueryProvider + { + private readonly ISession _session; + private readonly string entityName; + + public NHibernateQueryProvider(ISession session, QueryOptions queryOptions) + { + if (session == null) throw new ArgumentNullException("session"); + _session = session; + this.queryOptions = queryOptions; + } + + public NHibernateQueryProvider(ISession session, QueryOptions queryOptions,string entityName) + { + if (session == null) throw new ArgumentNullException("session"); + _session = session; + this.entityName = entityName; + this.queryOptions = queryOptions; + } + + + private static object ResultsFromCriteria(ICriteria criteria, Expression expression) + { + System.Type elementType = TypeSystem.GetElementType(expression.Type); + + return Activator.CreateInstance(typeof(CriteriaResultReader<>) + .MakeGenericType(elementType), criteria); + } + + public object TranslateExpression(Expression expression) + { + expression = Evaluator.PartialEval(expression); + expression = new BinaryBooleanReducer().Visit(expression); + expression = new AssociationVisitor((ISessionFactoryImplementor)_session.SessionFactory).Visit(expression); + expression = new InheritanceVisitor().Visit(expression); + expression = CollectionAliasVisitor.AssignCollectionAccessAliases(expression); + expression = new PropertyToMethodVisitor().Visit(expression); + expression = new BinaryExpressionOrderer().Visit(expression); + + NHibernateQueryTranslator translator = new NHibernateQueryTranslator(_session,entityName); + return translator.Translate(expression, this.queryOptions); + } + + public override object Execute(Expression expression) + { + var results = TranslateExpression(expression); + var criteria = results as ICriteria; + + if (criteria != null) + return ResultsFromCriteria(criteria, expression); + return results; + } + } +} \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Query.cs b/src/Libraries/NHibernate/NHibernate.Linq/Query.cs new file mode 100644 index 00000000000..1ea3952d07d --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Query.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace NHibernate.Linq +{ + /// + /// Generic IQueryable base class. See http://blogs.msdn.com/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx + /// + public class Query : INHibernateQueryable + { + private readonly QueryProvider provider; + private readonly Expression expression; + private readonly QueryOptions queryOptions; + + public Query(QueryProvider provider, QueryOptions queryOptions) + { + if (provider == null) throw new ArgumentNullException("provider"); + + this.provider = provider; + this.queryOptions = queryOptions; + this.expression = Expression.Constant(this); + } + + public Query(QueryProvider provider, Expression expression, QueryOptions queryOptions) + { + if (provider == null) throw new ArgumentNullException("provider"); + if (expression == null) throw new ArgumentNullException("expression"); + + if (!typeof(IQueryable).IsAssignableFrom(expression.Type)) + throw new ArgumentOutOfRangeException("expression"); + + this.provider = provider; + this.queryOptions = queryOptions; + this.expression = expression; + } + + Expression IQueryable.Expression + { + get { return this.expression; } + } + + System.Type IQueryable.ElementType + { + get { return typeof(T); } + } + + IQueryProvider IQueryable.Provider + { + get { return this.provider; } + } + + public QueryOptions QueryOptions + { + get { return queryOptions; } + } + + public IQueryable Expand(string path) + { + queryOptions.AddExpansion(path); + + return this; + } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)this.provider.Execute(this.expression)).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)this.provider.Execute(this.expression)).GetEnumerator(); + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/QueryOptions.cs b/src/Libraries/NHibernate/NHibernate.Linq/QueryOptions.cs new file mode 100644 index 00000000000..ad0b7481d7f --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/QueryOptions.cs @@ -0,0 +1,56 @@ +using System; + +namespace NHibernate.Linq +{ + /// + /// It provides methods for caching the results, and some extension methods for them. + /// + public class QueryOptions + { + private Action action; + + public QueryOptions() + { + this.action = delegate { }; + } + + public QueryOptions SetCachable(bool cachable) + { + action += criteria => criteria.SetCacheable(cachable); + return this; + } + public QueryOptions SetCacheMode(CacheMode mode) + { + action += criteria => criteria.SetCacheMode(mode); + return this; + } + public QueryOptions SetCacheRegion(string cacheRegion) + { + action += criteria => criteria.SetCacheRegion(cacheRegion); + return this; + } + public QueryOptions SetComment(string comment) + { + action += criteria => criteria.SetComment(comment); + return this; + } + public QueryOptions RegisterCustomAction(Action customAction) + { + action += customAction; + return this; + } + + internal void Execute(ICriteria criteria) + { + action(criteria); + } + + public void AddExpansion(string path) + { + action += criteria => + { + criteria.Fetch(SelectMode.Fetch, path); + }; + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/QueryProvider.cs b/src/Libraries/NHibernate/NHibernate.Linq/QueryProvider.cs new file mode 100644 index 00000000000..05645603e82 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/QueryProvider.cs @@ -0,0 +1,39 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using NHibernate.Linq.Util; + +namespace NHibernate.Linq +{ + /// + /// Generic IQueryProvider base class. See http://blogs.msdn.com/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx + /// + public abstract class QueryProvider : IQueryProvider + { + protected QueryOptions queryOptions; + + IQueryable IQueryProvider.CreateQuery(Expression expression) + { + return new Query(this, expression, queryOptions); + } + + IQueryable IQueryProvider.CreateQuery(Expression expression) + { + QueryOptions options = new QueryOptions(); + System.Type elementType = TypeSystem.GetElementType(expression.Type); + return (IQueryable)Activator.CreateInstance(typeof(Query<>).MakeGenericType(elementType), new object[] { this, expression, options }); + } + + T IQueryProvider.Execute(Expression expression) + { + return (T)this.Execute(expression); + } + + object IQueryProvider.Execute(Expression expression) + { + return this.Execute(expression); + } + + public abstract object Execute(Expression expression); + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/SqlClient/SqlClientExtensions.cs b/src/Libraries/NHibernate/NHibernate.Linq/SqlClient/SqlClientExtensions.cs new file mode 100644 index 00000000000..7f093e08791 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/SqlClient/SqlClientExtensions.cs @@ -0,0 +1,321 @@ +using System; + +namespace NHibernate.Linq.SqlClient +{ + /// + /// Provides static methods that represent functionality provided by MS SQL Server. + /// + public static class SqlClientExtensions + { + #region DateTime Functions + + /// + /// Returns an integer representing the day datepart of the specified date. + /// + /// + /// + /// + public static int Day(this IDbMethods methods, DateTime value) + { + return 0; + } + + /// + /// Returns an integer representing the day datepart of the specified date. + /// + /// + /// + /// + public static int Day(this IDbMethods methods, DateTime? value) + { + return 0; + } + + /// + /// Returns an integer that represents the month part of a specified date. + /// + /// + /// + /// + public static int Month(this IDbMethods methods, DateTime value) + { + return 0; + } + + /// + /// Returns an integer that represents the month part of a specified date. + /// + /// + /// + /// + public static int Month(this IDbMethods methods, DateTime? value) + { + return 0; + } + + /// + /// Returns an integer that represents the year part of a specified date. + /// + /// + /// + /// + public static int Year(this IDbMethods methods, DateTime value) + { + return 0; + } + + /// + /// Returns an integer that represents the year part of a specified date. + /// + /// + /// + /// + public static int Year(this IDbMethods methods, DateTime? value) + { + return 0; + } + + #endregion DateTime Functions + + #region Math Functions + + #endregion Math Functions + + #region String Functions + + /// + /// Returns the ASCII code value of the leftmost character of a character expression. + /// + /// + /// + /// + public static int Ascii(this IDbMethods methods, string value) + { + return 0; + } + + /// + /// Returns the ASCII code value of the leftmost character of a character expression. + /// + /// + /// + /// + public static int Ascii(this IDbMethods methods, char value) + { + return 0; + } + + /// + /// Returns the ASCII code value of the leftmost character of a character expression. + /// + /// + /// + /// + public static int Ascii(this IDbMethods methods, char? value) + { + return 0; + } + + /// + /// Converts an int ASCII code to a character. + /// + /// + /// + /// + public static char Char(this IDbMethods methods, int value) + { + return char.MinValue; + } + + /// + /// Converts an int ASCII code to a character. + /// + /// + /// + /// + public static char Char(this IDbMethods methods, int? value) + { + return char.MinValue; + } + + /// + /// Returns the starting position of the specified expression in a character string. + /// + /// + /// + /// + /// + public static int CharIndex(this IDbMethods methods, string value, char search) + { + return 0; + } + + /// + /// Returns the starting position of the specified expression in a character string. + /// + /// + /// + /// + /// + /// + public static int CharIndex(this IDbMethods methods, string value, char search, int start) + { + return 0; + } + + /// + /// Returns the starting position of the specified expression in a character string. + /// + /// + /// + /// + /// + public static int CharIndex(this IDbMethods methods, string value, string search) + { + return 0; + } + + /// + /// Returns the starting position of the specified expression in a character string. + /// + /// + /// + /// + /// + /// + public static int CharIndex(this IDbMethods methods, string value, string search, int start) + { + return 0; + } + + /// + /// Returns the left part of a character string with the specified number of characters. + /// + /// + /// + /// + /// + public static string Left(this IDbMethods methods, string value, int length) + { + return null; + } + + /// + /// Returns the number of characters of the specified string expression, excluding trailing blanks. + /// + /// + /// + /// + public static int Len(this IDbMethods methods, string value) + { + return 0; + } + + /// + /// Returns a character expression after converting uppercase character data to lowercase. + /// + /// + /// + /// + public static string Lower(this IDbMethods methods, string value) + { + return null; + } + + /// + /// Returns a character expression after it removes leading blanks. + /// + /// + /// + /// + public static string LTrim(this IDbMethods methods, string value) + { + return null; + } + + /// + /// Replaces all occurrences of a specified string value with another string value. + /// + /// + /// + /// + /// + /// + public static string Replace(this IDbMethods methods, string value, string search, string replace) + { + return null; + } + + /// + /// Repeats a string value a specified number of times. + /// + /// + /// + /// + /// + public static string Replicate(this IDbMethods methods, string value, int count) + { + return null; + } + + /// + /// Returns the reverse of a character expression. + /// + /// + /// + /// + public static string Reverse(this IDbMethods methods, string value) + { + return null; + } + + /// + /// Returns the right part of a character string with the specified number of characters. + /// + /// + /// + /// + /// + public static string Right(this IDbMethods methods, string value, int length) + { + return null; + } + + /// + /// Returns a character string after truncating all trailing blanks. + /// + /// + /// + /// + public static string RTrim(this IDbMethods methods, string value) + { + return null; + } + + /// + /// Returns part of a character, binary, text, or image expression. + /// + /// + /// + /// + /// + /// + public static string Substring(this IDbMethods methods, string value, int start, int length) + { + return null; + } + + /// + /// Returns a character expression with lowercase character data converted to uppercase. + /// + /// + /// + /// + public static string Upper(this IDbMethods methods, string value) + { + return null; + } + + #endregion String Functions + } +} \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Transform/LinqGroupingResultTransformer.cs b/src/Libraries/NHibernate/NHibernate.Linq/Transform/LinqGroupingResultTransformer.cs new file mode 100644 index 00000000000..2ddf608aeab --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Transform/LinqGroupingResultTransformer.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using NHibernate.Transform; + +namespace NHibernate.Linq.Transform +{ + /// + /// Transforms critieria query results into a collection of grouped objects. + /// + public class LinqGroupingResultTransformer : IResultTransformer + { + private readonly System.Type groupingType; + private readonly IDictionary groups; + private readonly String propertyName; + + /// + /// Initializes a new instance of the class. + /// + /// A representing the type of collection to transform. + /// The name of the property to be used as a key for the purpose of grouping. + public LinqGroupingResultTransformer(System.Type type, String propertyName) + { + System.Type[] args = type.GetGenericArguments(); + groupingType = typeof(Grouping<,>).MakeGenericType(args[0], args[1]); + groups = new Dictionary(); + this.propertyName = propertyName; + + int index = propertyName.IndexOf('.'); + if (index > -1) + { + this.propertyName = propertyName.Substring(index + 1); + } + } + + #region IResultTransformer Members + + /// + /// Transforms the query result collection. + /// + /// An of objects. + /// A transformed object. + public IList TransformList(IList collection) + { + while (collection.Contains(null)) + { + collection.Remove(null); + } + + return collection; + } + + /// + /// Transforms each query result. + /// + /// An array of query result values. + /// A array of column aliases. + /// An initialized with the values from the specified tuple. + public object TransformTuple(object[] tuple, string[] aliases) + { + object value = tuple[0].GetType().GetProperty(propertyName).GetValue(tuple[0], null); + String key = String.Format("{0}", value); + + if (groups.ContainsKey(key)) + { + groups[key].Add(tuple[1]); + return null; + } + else + { + var group = (IGrouping)Activator.CreateInstance(groupingType, value); + group.Add(tuple[1]); + groups[key] = group; + return group; + } + } + + #endregion + } + + /// + /// Provides a method for adding individual objects to a collection of grouped objects. + /// + internal interface IGrouping + { + /// + /// Adds an object to the current group. + /// + /// The to add. + void Add(object item); + } + + /// + /// Represents a collection of objects that have a common key. + /// + /// + /// + internal class Grouping : IGrouping, IGrouping + { + private readonly TKey key; + private readonly IList list = new List(); + + /// + /// Initializes a new instance of the class. + /// + /// + public Grouping(TKey key) + { + this.key = key; + } + + #region IGrouping Members + + /// + /// Adds an object to the current group. + /// + /// The to add. + public void Add(object item) + { + list.Add((TElement)item); + } + + #endregion + + #region IGrouping Members + + /// + /// Gets the key of the . + /// + public TKey Key + { + get { return key; } + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An that can be used to iterate through the collection. + public IEnumerator GetEnumerator() + { + return list.GetEnumerator(); + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + + /// + /// Returns a that represents the current . + /// + /// A that represents the current . + public override string ToString() + { + return String.Format("Key = {0}", Key); + } + } +} \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Transform/LinqJoinResultsTransformer.cs b/src/Libraries/NHibernate/NHibernate.Linq/Transform/LinqJoinResultsTransformer.cs new file mode 100644 index 00000000000..f738eb4463b --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Transform/LinqJoinResultsTransformer.cs @@ -0,0 +1,32 @@ +using System.Collections; + +namespace NHibernate.Linq.Transform +{ + public class LinqJoinResultsTransformer : NHibernate.Transform.IResultTransformer + { + private readonly System.Type _entityType; + + public LinqJoinResultsTransformer(System.Type entityType) + { + _entityType = entityType; + } + + public IList TransformList(IList collection) + { + return collection; + } + + public object TransformTuple(object[] tuple, string[] aliases) + { + foreach (object obj in tuple) + { + if (obj != null && obj.GetType() == _entityType) + { + return obj; + } + } + + return null; + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Transform/TypeSafeConstructorMemberInitResultTransformer.cs b/src/Libraries/NHibernate/NHibernate.Linq/Transform/TypeSafeConstructorMemberInitResultTransformer.cs new file mode 100644 index 00000000000..cd8c773d6a3 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Transform/TypeSafeConstructorMemberInitResultTransformer.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using NHibernate.Linq.Util; + +namespace NHibernate.Transform +{ + [Serializable] + public class TypeSafeConstructorMemberInitResultTransformer : IResultTransformer + { + private readonly Expression expression; + + public TypeSafeConstructorMemberInitResultTransformer(NewExpression expression) + { + this.expression = expression; + } + + public TypeSafeConstructorMemberInitResultTransformer(MemberInitExpression expression) + { + this.expression = expression; + } + + public object TransformTuple(object[] tuple, string[] aliases) + { + try + { + int argumentCount; + switch (expression.NodeType) + { + case ExpressionType.New: + return InvokeConstructor((NewExpression)expression, tuple, out argumentCount); + + case ExpressionType.MemberInit: + return InvokeMemberInitExpression((MemberInitExpression)expression, tuple, out argumentCount); + + default: + throw new NotSupportedException(); + } + } + catch (Exception e) + { + throw new QueryException( + "could not instantiate: " + + expression.Type.FullName, + e); + } + } + + private object InvokeConstructor(NewExpression expression, object[] args, out int argumentCount) + { + object valueToSet; + int nestedArgumentCount; + + argumentCount = 0; + ArrayList argList = new ArrayList(); + + int i = 0; + foreach (var arg in expression.Arguments) + { + switch (arg.NodeType) + { + case ExpressionType.New: + valueToSet = InvokeConstructor((NewExpression)arg, args.Skip(i).ToArray(), out nestedArgumentCount); + i += nestedArgumentCount; + break; + + case ExpressionType.MemberInit: + valueToSet = InvokeMemberInitExpression((MemberInitExpression)arg, + args.Skip(i).ToArray(), out nestedArgumentCount); + i += nestedArgumentCount; + break; + + default: + valueToSet = LinqUtil.ChangeType(args[i], arg.Type); + i++; + break; + } + argList.Add(valueToSet); + } + + argumentCount = i; + return expression.Constructor.Invoke(argList.ToArray()); + } + + private object InvokeMemberInitExpression(MemberInitExpression expression, object[] args, out int argumentCount) + { + object valueToSet; + int nestedArgumentCount, constructorArgumentCount; + + argumentCount = 0; + object instance = InvokeConstructor(expression.NewExpression, args, out constructorArgumentCount); + + int i = constructorArgumentCount; + foreach (MemberAssignment binding in expression.Bindings) + { + switch (binding.Expression.NodeType) + { + case ExpressionType.New: + valueToSet = InvokeConstructor((NewExpression)binding.Expression, + args.Skip(i).ToArray(), out nestedArgumentCount); + i += nestedArgumentCount; + break; + + case ExpressionType.MemberInit: + valueToSet = InvokeMemberInitExpression((MemberInitExpression)binding.Expression, + args.Skip(i).ToArray(), out nestedArgumentCount); + i += nestedArgumentCount; + break; + + default: + valueToSet = args[i]; + i++; + break; + } + SetValue(binding.Member, instance, valueToSet); + } + + argumentCount = i; + return instance; + } + + /// + /// Sets the value of the field or property represented by the specified + /// for the supplied object instance. + /// + /// A object. + /// An instance of an object. + /// The value to set on the specified object. + private void SetValue(MemberInfo memberInfo, object instance, object valueToSet) + { + var field = memberInfo as FieldInfo; + if (field != null) + { + field.SetValue(instance, LinqUtil.ChangeType(valueToSet, field.FieldType)); + } + else + { + var prop = memberInfo as PropertyInfo; + prop.SetValue(instance, LinqUtil.ChangeType(valueToSet, prop.PropertyType), null); + } + } + + public IList TransformList(IList collection) + { + return collection; + } + } +} \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Util/CriteriaUtil.cs b/src/Libraries/NHibernate/NHibernate.Linq/Util/CriteriaUtil.cs new file mode 100644 index 00000000000..2290382468c --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Util/CriteriaUtil.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using NHibernate.Criterion; +using NHibernate.Engine; +using NHibernate.Impl; +using NHibernate.Loader.Criteria; +using NHibernate.Persister.Entity; +using NHibernate.Transform; + +namespace NHibernate.Linq.Util +{ + public static class CriteriaUtil + { + #region Extension Methods + + public static ICriteriaQuery GenerateCriteriaQuery(this ICriteria criteria, ISessionFactory sessionFactory, string rootEntityName) + { + return new CriteriaQueryTranslator( + (ISessionFactoryImplementor)sessionFactory, + (CriteriaImpl)criteria, + rootEntityName, "this"); + } + + public static void SetProjectionIfNotNull(this ICriteria criteria, IProjection projection) + { + if (projection != null) + criteria.SetProjection(projection); + } + + public static void SetResultTransformerIfNotNull(this ICriteria criteria, IResultTransformer transformer) + { + if (transformer != null) + criteria.SetResultTransformer(transformer); + else + criteria.SetResultTransformer(new RootEntityResultTransformer()); + } + + public static void Add(this ICriteria criteria, IEnumerable criterion) + { + foreach (ICriterion c in criterion) + { + criteria.Add(c); + } + } + + public static string GetEntityOrClassName(this ICriteria criteria) + { + if (criteria is CriteriaImpl) + { + return ((CriteriaImpl)criteria).EntityOrClassName; + } + + if (criteria is DetachedCriteriaAdapter) + { + var adapter = (DetachedCriteriaAdapter)criteria; + return adapter.DetachedCriteria.EntityOrClassName; + } + throw new NotSupportedException("criteria must be of type CriteriaImpl or DetachedCriteriaAdapter."); + } + + public static IProjection GetProjection(this ICriteria criteria) + { + var impl = criteria as CriteriaImpl; + if (impl != null) + { + return impl.Projection; + } + return null; + } + + public static System.Type GetRootType(this ICriteria criteria) + { + if (criteria is DetachedCriteriaAdapter) + { + var adapter = (DetachedCriteriaAdapter)criteria; + return GetRootType(adapter.DetachedCriteria, adapter.Session); + } + return GetRootType(GetRootCriteria(criteria)); + } + + #endregion + + public static ISessionImplementor GetSession(ICriteria criteria) + { + return GetRootCriteria(criteria).Session; + } + + private static CriteriaImpl GetRootCriteria(ICriteria criteria) + { + var impl = criteria as CriteriaImpl; + if (impl != null) + return impl; + return GetRootCriteria(((CriteriaImpl.Subcriteria)criteria).Parent); + } + + private static System.Type GetRootType(CriteriaImpl criteria) + { + if (criteria.Session == null) + throw new InvalidOperationException("Could not get root type on criteria that is not attached to a session"); + + ISessionFactoryImplementor factory = criteria.Session.Factory; + + //TODO: need to cache the entityName meta data + var entityNames = factory.GetEntityNameMetaData(); + + if (!entityNames.ContainsKey(criteria.EntityOrClassName)) + throw new InvalidOperationException("Could not find entity named: " + criteria.EntityOrClassName); + + return entityNames[criteria.EntityOrClassName]; + } + + private static System.Type GetRootType(DetachedCriteria criteria, ISession session) + { + ISessionFactoryImplementor factory = (ISessionFactoryImplementor)session.SessionFactory; + IEntityPersister persister = factory.GetEntityPersister(criteria.EntityOrClassName); + if (persister == null) + throw new InvalidOperationException("Could not find entity named: " + criteria.EntityOrClassName); + + return persister.MappedClass; + } + } +} diff --git a/lib/nhibernate.linq/DetachedCriteriaAdapter.cs b/src/Libraries/NHibernate/NHibernate.Linq/Util/DetachedCriteriaAdapter.cs similarity index 83% rename from lib/nhibernate.linq/DetachedCriteriaAdapter.cs rename to src/Libraries/NHibernate/NHibernate.Linq/Util/DetachedCriteriaAdapter.cs index 5762ba1d5a9..5e3f7f58308 100644 --- a/lib/nhibernate.linq/DetachedCriteriaAdapter.cs +++ b/src/Libraries/NHibernate/NHibernate.Linq/Util/DetachedCriteriaAdapter.cs @@ -1,6 +1,8 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; using NHibernate.Criterion; using NHibernate.SqlCommand; using NHibernate.Transform; @@ -151,7 +153,8 @@ public ICriteria SetComment(string comment) throw new NotSupportedException(); } - public ICriteria SetFetchMode(string associationPath, FetchMode mode) + [Obsolete("Use Fetch instead")] + public ICriteria SetFetchMode(string associationPath, FetchMode mode) { return detachedCriteria.SetFetchMode(associationPath, mode).Adapt(session); } @@ -240,11 +243,34 @@ public IFutureValue FutureValue() throw new NotSupportedException(); } - #endregion + public Task ListAsync(CancellationToken cancellationToken = default(CancellationToken)) { + throw new NotSupportedException(); + } + + public Task UniqueResultAsync(CancellationToken cancellationToken = default(CancellationToken)) { + throw new NotSupportedException(); + } - #region ICloneable Members + public Task ListAsync(IList results, CancellationToken cancellationToken = default(CancellationToken)) { + throw new NotSupportedException(); + } + + public Task> ListAsync(CancellationToken cancellationToken = default(CancellationToken)) { + throw new NotSupportedException(); + } - public object Clone() + public Task UniqueResultAsync(CancellationToken cancellationToken = default(CancellationToken)) { + throw new NotSupportedException(); + } + + IFutureEnumerable ICriteria.Future() { + throw new NotSupportedException(); + } + #endregion + + #region ICloneable Members + + public object Clone() { throw new NotSupportedException(); } @@ -277,5 +303,6 @@ public ICriteria SetReadOnly(bool readOnly) _readOnlyInitialized = true; return this; } + } } \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Util/LinqUtil.cs b/src/Libraries/NHibernate/NHibernate.Linq/Util/LinqUtil.cs new file mode 100644 index 00000000000..98add190c48 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Util/LinqUtil.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +namespace NHibernate.Linq.Util +{ + /// + /// Provides static utility methods that aid in evaluating expression trees. + /// + public static class LinqUtil + { + /// + /// Creates a collection of type T by invoking a delegate method during + /// enumeration that return each item, begining with an initialValue. + /// + /// The type of collection being created. + /// A delegate method to invoke. + /// The first item in the collection. + /// An collection of type T. + public static IEnumerable Iterate(Func func, T initialValue) + { + T value = initialValue; + while (true) + { + yield return value; + value = func(value); + } + } + + /// + /// Returns an with the specified + /// and whose value is equivalent to the specified object. + /// + /// An that implements the interface. + /// A . + /// An object whose is conversionType and whose value is equivalent + /// to value, or null, if value is null and conversionType is not a value type. + public static object ChangeType(object value, System.Type conversionType) + { + // have to use IsAssignableFrom() due to proxy classes + if (value != null && !conversionType.IsAssignableFrom(value.GetType())) + { + if (IsNullableType(conversionType)) + { + System.Type arg = conversionType.GetGenericArguments()[0]; + if (arg.IsEnum) + { + if (value is string) + { + value = Activator.CreateInstance(conversionType, Enum.Parse(arg, value as string)); + } + else + { + value = Activator.CreateInstance(conversionType, Enum.ToObject(arg, value)); + } + } + else + { + value = Activator.CreateInstance(conversionType, Convert.ChangeType(value, arg)); + } + } + else + { + if (conversionType.IsEnum) + { + if (value is string) + { + value = Enum.Parse(conversionType, value as string); + } + else + { + value = Enum.ToObject(conversionType, value); + } + } + else + { + value = Convert.ChangeType(value, conversionType); + } + } + } + + return value; + } + + /// + /// Determines if the specified type is a type. + /// + /// A to check. + /// True if the type is a type, otherwise false. + public static bool IsNullableType(System.Type type) + { + return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); + } + + /// + /// Determines if the specified type is an anonymous type. + /// + /// A to check. + /// True if the type is an anonymous type, otherwise false. + public static bool IsAnonymousType(System.Type type) + { + return type != null && type.Name.StartsWith("<"); + } + + /// + /// Encodes an for use in SQL statements. + /// + /// The value to encode. + /// A SQL encoded value. + public static string SqlEncode(object value) + { + if (value != null) + { + System.Type type = value.GetType(); + + if (IsNullableType(type)) + { + value = type.GetProperty("Value").GetValue(value, null); + return SqlEncode(value); + } + + switch (System.Type.GetTypeCode(type)) + { + case TypeCode.Boolean: + return ((bool)value) ? "1" : "0"; + case TypeCode.Byte: + case TypeCode.Decimal: + case TypeCode.Double: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.SByte: + case TypeCode.Single: + return value.ToString(); + case TypeCode.DBNull: + case TypeCode.Empty: + return "null"; + default: + return String.Format("'{0}'", value.ToString().Replace("'", "''")); + } + } + + return "null"; + } + + public static Expression StripQuotes(Expression e) + { + while (e.NodeType == ExpressionType.Quote) + e = ((UnaryExpression)e).Operand; + return e; + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Util/QueryUtil.cs b/src/Libraries/NHibernate/NHibernate.Linq/Util/QueryUtil.cs new file mode 100644 index 00000000000..2cdd9b006d7 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Util/QueryUtil.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using NHibernate.Criterion; +using NHibernate.Linq.Expressions; +using Expression = System.Linq.Expressions.Expression; + +namespace NHibernate.Linq.Util +{ + public class QueryUtil + { + public static object GetExpressionValue(Expression expression) + { + var constExpr = expression as ConstantExpression; + if (constExpr != null) + return constExpr.Value; + + return Expression.Lambda(typeof(Func<>).MakeGenericType(expression.Type), expression) + .Compile().DynamicInvoke(); + } + + public static List GetParameters(Expression expr) + { + var list = new List(); + GetParameters(expr, list); + return list; + } + + public static object[] GetMethodParameterValues(MethodCallExpression call) + { + System.Type[] paramTypes = null; + return GetMethodParameterValues(call, out paramTypes); + } + + public static object[] GetMethodParameterValues(MethodCallExpression call, out System.Type[] types) + { + ConstantExpression ce; + object[] values = null; + types = null; + + if (call != null) + { + var valueList = new List(); + var typeList = new List(); + + for (int i = 0; i < call.Arguments.Count; i++) + { + ce = call.Arguments[i] as ConstantExpression; + if (ce != null) + { + valueList.Add(ce.Value); + typeList.Add(ce.Type); + } + } + if (valueList.Count > 0) + { + values = valueList.ToArray(); + types = typeList.ToArray(); + } + } + + return values; + } + + public static SqlFunctionExpression GetFunctionCriteria(MethodCallExpression call, ICriterion criterion, + SqlFunctionExpression rightFunction) + { + System.Type[] paramTypes = null; + object[] paramValues = GetMethodParameterValues(call, out paramTypes); + + int propertyPosition = 0; + string methodName = QueryUtil.GetMethodName(call, out propertyPosition); + + return new SqlFunctionExpression(methodName, call.Method.ReturnType, paramValues, paramTypes, criterion, + propertyPosition, rightFunction); + } + + public static void GetParameters(Expression expr, List list) + { + if (expr is ParameterExpression) + { + var pe = expr as ParameterExpression; + if (!list.Contains(pe)) + { + list.Add(pe); + } + } + else if (expr is MemberExpression) + { + GetParameters(((MemberExpression)expr).Expression, list); + } + else if (expr is UnaryExpression) + { + GetParameters(((UnaryExpression)expr).Operand, list); + } + else if (expr is BinaryExpression) + { + var be = expr as BinaryExpression; + GetParameters(be.Left, list); + GetParameters(be.Right, list); + } + } + + public static string GetMethodName(MethodCallExpression call, out int propertyPosition) + { + object[] attribs = call.Method.GetCustomAttributes(typeof(SqlFunctionAttribute), false); + var attrib = attribs.FirstOrDefault() as SqlFunctionAttribute; + string methodName = call.Method.Name; + propertyPosition = 0; + + if (attrib != null) + { + if (!String.IsNullOrEmpty(attrib.Owner)) + methodName = String.Format("{0}.{1}", attrib.Owner, methodName); + propertyPosition = attrib.PropertyPosition; + } + else + { + // provide mapping of System methods to SQL functions + switch (methodName.ToLower()) + { + case "tolower": + methodName = "lower"; + break; + case "toupper": + methodName = "upper"; + break; + case "indexof": + case "charindex": + methodName = "charindex"; + propertyPosition = 1; + break; + } + } + + return methodName; + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Util/SessionFactoryUtil.cs b/src/Libraries/NHibernate/NHibernate.Linq/Util/SessionFactoryUtil.cs new file mode 100644 index 00000000000..eb9bc5bec95 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Util/SessionFactoryUtil.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using NHibernate.Engine; +using NHibernate.Metadata; + +namespace NHibernate.Linq.Util +{ + public static class SessionFactoryUtil + { + public static IDictionary GetProxyMetaData(this ISessionFactoryImplementor factory, IDictionary metaData) + { + var dict = new Dictionary(); + foreach (var item in metaData) + { + if (item.Value.HasProxy) + { + var proxyType = factory.GetEntityPersister(item.Key).ConcreteProxyClass; + if (proxyType != item.Value.MappedClass && !dict.ContainsKey(proxyType)) + { + dict.Add(proxyType, item.Key); + } + } + } + return dict; + } + + public static IDictionary GetEntityNameMetaData(this ISessionFactoryImplementor factory) + { + var metaData = factory.GetAllClassMetadata(); + + var dict = new Dictionary(); + foreach (var item in metaData) + { + var type = item.Value.MappedClass; + + dict.Add(item.Key, type); + if (item.Value.HasProxy) + { + var proxyType = factory.GetEntityPersister(item.Key).ConcreteProxyClass; + if (proxyType != type && !dict.ContainsKey(proxyType.FullName)) + { + dict.Add(proxyType.FullName, proxyType); + } + } + } + return dict; + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Util/TypeSystem.cs b/src/Libraries/NHibernate/NHibernate.Linq/Util/TypeSystem.cs new file mode 100644 index 00000000000..791cf407a4e --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Util/TypeSystem.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; + +namespace NHibernate.Linq.Util +{ + /// + /// http://blogs.msdn.com/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx + /// + public static class TypeSystem + { + public static System.Type GetElementType(System.Type seqType) + { + System.Type ienum = FindIEnumerable(seqType); + if (ienum == null) return seqType; + return ienum.GetGenericArguments()[0]; + } + + private static System.Type FindIEnumerable(System.Type seqType) + { + if (seqType == null || seqType == typeof(string)) + return null; + + if (seqType.IsArray) + return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType()); + + if (seqType.IsGenericType) + { + foreach (System.Type arg in seqType.GetGenericArguments()) + { + System.Type ienum = typeof(IEnumerable<>).MakeGenericType(arg); + if (ienum.IsAssignableFrom(seqType)) + { + return ienum; + } + } + } + + System.Type[] ifaces = seqType.GetInterfaces(); + if (ifaces != null && ifaces.Length > 0) + { + foreach (System.Type iface in ifaces) + { + System.Type ienum = FindIEnumerable(iface); + if (ienum != null) return ienum; + } + } + + if (seqType.BaseType != null && seqType.BaseType != typeof(object)) + { + return FindIEnumerable(seqType.BaseType); + } + return null; + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/AssociationVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/AssociationVisitor.cs new file mode 100644 index 00000000000..95162c03d1e --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/AssociationVisitor.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using NHibernate.Engine; +using NHibernate.Linq.Expressions; +using NHibernate.Linq.Util; +using NHibernate.Metadata; +using NHibernate.Type; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Preprocesses an expression tree replacing MemberAccessExpressions and ParameterExpressions with + /// NHibernate-specific PropertyAccessExpressions and EntityExpressions respectively. + /// + public class AssociationVisitor : ExpressionVisitor + { + private readonly ISessionFactoryImplementor _sessionFactory; + private readonly IDictionary _metaData; + private readonly IDictionary _proxyTypes; + + public AssociationVisitor(ISessionFactoryImplementor sessionFactory) + { + _sessionFactory = sessionFactory; + _metaData = _sessionFactory.GetAllClassMetadata(); + _proxyTypes = _sessionFactory.GetProxyMetaData(_metaData); + } + + private IClassMetadata GetMetaData(System.Type type) + { + if (LinqUtil.IsAnonymousType(type)) + return null; + + string entityName = _sessionFactory.TryGetGuessEntityName(type); + + if (!String.IsNullOrEmpty(entityName) && _metaData.ContainsKey(entityName)) + return _metaData[entityName]; + + if (_proxyTypes.ContainsKey(type)) + return _metaData[_proxyTypes[type]]; + + return null; + } + + private EntityExpression GetParentExpression(MemberExpression expr, out string memberName, out IType nhibernateType) + { + memberName = null; + nhibernateType = null; + + CollectionAccessExpression collectionExpr = expr.Expression as CollectionAccessExpression; + if (collectionExpr != null) + { + return null; + } + + PropertyAccessExpression propExpr = expr.Expression as PropertyAccessExpression; + if (propExpr != null) + { + memberName = propExpr.Name + "." + expr.Member.Name; + nhibernateType = propExpr.Expression.MetaData.GetPropertyType(memberName); + return propExpr.Expression; + } + + EntityExpression entityExpr = expr.Expression as EntityExpression; + if (entityExpr != null) + { + memberName = expr.Member.Name; + nhibernateType = entityExpr.MetaData.GetPropertyType(memberName); + return entityExpr; + } + + return null; + } + + private string AssociationPathForEntity(MemberExpression expr) + { + PropertyAccessExpression propExpr = expr.Expression as PropertyAccessExpression; + if (propExpr != null) + return propExpr.Name + "." + expr.Member.Name; + + EntityExpression entityExpr = expr.Expression as EntityExpression; + if (entityExpr != null && entityExpr.Expression != null) + return entityExpr.Alias + "." + expr.Member.Name; + + return expr.Member.Name; + } + + protected override Expression VisitMemberAccess(MemberExpression expr) + { + expr = (MemberExpression)base.VisitMemberAccess(expr); + + IClassMetadata metaData = GetMetaData(expr.Type); + if (metaData != null) + { + string associationPath = AssociationPathForEntity(expr); + return new EntityExpression(associationPath, expr.Member.Name, expr.Type, metaData, expr.Expression); + } + + string memberName; + IType nhibernateType; + EntityExpression parentExpression = GetParentExpression(expr, out memberName, out nhibernateType); + + if (parentExpression != null) + { + if (nhibernateType.IsCollectionType) + { + CollectionType collectionType = (CollectionType)nhibernateType; + IType nhElementType = collectionType.GetElementType((ISessionFactoryImplementor)_sessionFactory); + + System.Type elementType = nhElementType.ReturnedClass; + IClassMetadata elementMetaData = GetMetaData(elementType); + + EntityExpression elementExpression = null; + if (elementMetaData != null) + elementExpression = new EntityExpression(null, memberName, elementType, elementMetaData, null); + + return new CollectionAccessExpression(memberName, expr.Type, nhibernateType, parentExpression, elementExpression); + } + + return new PropertyAccessExpression(memberName, expr.Type, nhibernateType, parentExpression); + } + + return expr; + } + + protected override Expression VisitParameter(ParameterExpression expr) + { + IClassMetadata metaData = GetMetaData(expr.Type); + if (metaData != null) + return new EntityExpression(null, expr.Name, expr.Type, metaData, null); + + return expr; + } + + protected override Expression VisitConstant(ConstantExpression expr) + { + IQueryable query = expr.Value as IQueryable; + if (query != null) + { + return new QuerySourceExpression("this", query); + } + return expr; + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryBooleanReducer.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryBooleanReducer.cs new file mode 100644 index 00000000000..f462671020f --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryBooleanReducer.cs @@ -0,0 +1,74 @@ +using System.Linq.Expressions; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Preprocesses an expression tree replacing binary boolean expressions with unary expressions. + /// + public class BinaryBooleanReducer : ExpressionVisitor + { + //this class simplifies this: + // timesheet.Entries.Any() == true + //to this: + // timesheet.Entries.Any() + + private Expression ProcessBinaryExpression(Expression exprToCompare, Expression exprToReturn, ExpressionType nodeType, Expression original) + { + BooleanConstantFinder visitor = new BooleanConstantFinder(); + visitor.Visit(exprToCompare); + + if (visitor.Constant.HasValue) + { + switch (nodeType) + { + case ExpressionType.Equal: + return visitor.Constant.Value ? exprToReturn : Expression.Not(exprToReturn); + case ExpressionType.NotEqual: + return visitor.Constant.Value ? Expression.Not(exprToReturn) : exprToReturn; + case ExpressionType.Or: + case ExpressionType.OrElse: + return visitor.Constant.Value ? Expression.Constant(true) : exprToReturn; + case ExpressionType.And: + case ExpressionType.AndAlso: + return visitor.Constant.Value ? exprToReturn : Expression.Constant(false); + default: + return original; + } + } + else + return original; + } + + protected override Expression VisitBinary(BinaryExpression expr) + { + Expression e = ProcessBinaryExpression(expr.Left, expr.Right, expr.NodeType, expr); + if (e != expr) + return e; + e = ProcessBinaryExpression(expr.Right, expr.Left, expr.NodeType, expr); + if (e != expr) + return e; + return base.VisitBinary(expr); + + } + + class BooleanConstantFinder : ExpressionVisitor + { + private bool _isNestedBinaryExpression; + + public bool? Constant { get; private set; } + + protected override Expression VisitConstant(ConstantExpression c) + { + if (c.Type == typeof(bool) && !_isNestedBinaryExpression) + Constant = (bool)c.Value; + return c; + } + + protected override Expression VisitBinary(BinaryExpression b) + { + _isNestedBinaryExpression = true; + return b; + } + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryCriterionDelegates.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryCriterionDelegates.cs new file mode 100644 index 00000000000..af83ed22c50 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryCriterionDelegates.cs @@ -0,0 +1,40 @@ +using NHibernate.Criterion; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Represents a method that returns an + /// object that compares one property to another property using a binary expression. + /// + /// The name of the property to compare on the left hand side of the expression. + /// The name of the property to compare on the right hand side of the expression. + /// An initialized object. + public delegate ICriterion ComparePropToProp(string propertyName, string otherPropertyName); + + /// + /// Represents a method that returns an + /// object that compares a property to a constant value using a binary expression. + /// + /// The name of the property to compare on the left hand side of the expression. + /// The constant value used for the right hand side of the expression. + /// An initialized object. + public delegate ICriterion ComparePropToValue(string propertyName, object value); + + /// + /// Represents a method that returns an + /// object that compares a value to a criteria using a binary expression. + /// + /// The value on the left hand side of the expression. + /// The used for the right hand side of the expression. + /// An initialized object. + public delegate ICriterion CompareValueToCriteria(object value, DetachedCriteria criteria); + + /// + /// Represents a method that returns an + /// object that compares a property to a criteria using a binary expression. + /// + /// The name of the property to compare on the left hand side of the expression. + /// The used for the right hand side of the expression. + /// An initialized object. + public delegate ICriterion ComparePropToCriteria(string propertyName, DetachedCriteria criteria); +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryCriterionType.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryCriterionType.cs new file mode 100644 index 00000000000..58a9e918dcc --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryCriterionType.cs @@ -0,0 +1,10 @@ +namespace NHibernate.Linq.Visitors +{ + public enum BinaryCriterionType + { + None, + Value, + Property, + Criteria + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryCriterionVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryCriterionVisitor.cs new file mode 100644 index 00000000000..1baf350e846 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryCriterionVisitor.cs @@ -0,0 +1,154 @@ +using System; +using System.Linq.Expressions; +using NHibernate.Criterion; +using NHibernate.Linq.Expressions; +using NHibernate.Linq.Util; +using Expression = System.Linq.Expressions.Expression; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Visits a BinaryExpression providing the appropriate NHibernate ICriterion. + /// + public class BinaryCriterionVisitor : NHibernateExpressionVisitor + { + private readonly ICriteria rootCriteria; + private readonly ISession session; + + public BinaryCriterionVisitor(ICriteria rootCriteria, ISession session) + { + this.rootCriteria = rootCriteria; + this.session = session; + } + + public System.Type ConvertTo { get; private set; } + + public BinaryCriterionType Type { get; private set; } + + public object Value { get; private set; } + + public string Name { get; private set; } + + public DetachedCriteria Criteria { get; private set; } + + protected override Expression VisitMethodCall(MethodCallExpression expr) + { + Type = BinaryCriterionType.Criteria; + + //TODO: don't hardcode this alias 'sub' + Criteria = DetachedCriteria.ForEntityName(rootCriteria.GetEntityOrClassName(), "sub"); + + EntityExpression rootEntity = EntityExpressionVisitor.RootEntity(expr); + if (rootEntity != null) + { + string identifierName = rootEntity.MetaData.IdentifierPropertyName; + Criteria.Add(Restrictions.EqProperty(rootCriteria.Alias + "." + identifierName, "sub." + identifierName)); + } + + if (SelectArgumentsVisitor.SupportsMethod(expr.Method.Name)) + { + var projectionVisitor = new SelectArgumentsVisitor(Criteria.Adapt(session), session); + projectionVisitor.Visit(expr); + Criteria.SetProjection(projectionVisitor.Projection); + } + + return expr; + } + + protected override Expression VisitMemberAccess(MemberExpression expr) + { + Type = BinaryCriterionType.Property; + Name = expr.Member.Name; + return expr; + } + + protected override Expression VisitConstant(ConstantExpression expr) + { + Type = BinaryCriterionType.Value; + Value = QueryUtil.GetExpressionValue(expr); + return expr; + } + + protected override Expression VisitEntity(EntityExpression expr) + { + Type = BinaryCriterionType.Property; + Name = MemberNameVisitor.GetMemberName(rootCriteria, expr); + return expr; + } + + protected override Expression VisitPropertyAccess(PropertyAccessExpression expr) + { + Type = BinaryCriterionType.Property; + Name = MemberNameVisitor.GetMemberName(rootCriteria, expr); + return expr; + } + + protected override Expression VisitCollectionAccess(CollectionAccessExpression expr) + { + return VisitPropertyAccess(expr); + } + + protected override Expression VisitUnary(UnaryExpression expr) + { + if (expr.NodeType == ExpressionType.Convert) + { + //convert to the type of the operand, not the type of the conversion + ConvertTo = expr.Operand.Type; + Visit(expr.Operand); + } + + return expr; + } + + public static ICriterion GetBinaryCriteria( + ICriteria rootCriteria, + ISession session, + BinaryExpression expr, + ComparePropToValue comparePropToValue, + ComparePropToProp comparePropToProp, + CompareValueToCriteria compareValueToCriteria, + ComparePropToCriteria comparePropToCriteria) + { + var left = new BinaryCriterionVisitor(rootCriteria, session); + var right = new BinaryCriterionVisitor(rootCriteria, session); + + left.Visit(expr.Left); + right.Visit(expr.Right); + + //the query should have been preprocessed so that + //only the following combinations are possible: + // LEFT RIGHT + // ======================== + // property value + // property property + // property criteria + // value criteria + // criteria criteria <== not supported yet + + switch (left.Type) + { + case BinaryCriterionType.Property: + switch (right.Type) + { + case BinaryCriterionType.Value: + object val = right.Value; + if (left.ConvertTo != null) + val = LinqUtil.ChangeType(val, left.ConvertTo); + return comparePropToValue(left.Name, val); + + case BinaryCriterionType.Property: + return comparePropToProp(left.Name, right.Name); + + case BinaryCriterionType.Criteria: + return comparePropToCriteria(left.Name, right.Criteria); + } + break; + + case BinaryCriterionType.Value: + return compareValueToCriteria(left.Value, right.Criteria); + } + + throw new NotSupportedException("Could not understand: " + expr); + } + } +} \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryExpressionOrderer.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryExpressionOrderer.cs new file mode 100644 index 00000000000..481fd45f9ec --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/BinaryExpressionOrderer.cs @@ -0,0 +1,140 @@ +using System.Linq.Expressions; +using NHibernate.Linq.Expressions; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Preprocesses an expression tree ordering binary expressions in accordance with the . + /// + public class BinaryExpressionOrderer : NHibernateExpressionVisitor + { + // This class makes sure binary expressions are in one of these configurations + // so that the BinaryCriterionVisitor can correctly process it. + // LEFT RIGHT + // ======================== + // property value + // property property + // property criteria + // value criteria + // criteria criteria + + private ExpressionType ReflectExpressionType(ExpressionType type) + { + switch (type) + { + case ExpressionType.LessThan: + return ExpressionType.GreaterThan; + + case ExpressionType.LessThanOrEqual: + return ExpressionType.GreaterThanOrEqual; + + case ExpressionType.GreaterThan: + return ExpressionType.LessThan; + + case ExpressionType.GreaterThanOrEqual: + return ExpressionType.LessThanOrEqual; + + case ExpressionType.Equal: + return ExpressionType.Equal; + + case ExpressionType.NotEqual: + return ExpressionType.NotEqual; + + default: + return type; + } + } + + private Expression Swap(BinaryExpression expr) + { + ExpressionType nodeType = ReflectExpressionType(expr.NodeType); + return Expression.MakeBinary(nodeType, expr.Right, expr.Left, expr.IsLiftedToNull, expr.Method, expr.Conversion); + } + + protected override Expression VisitBinary(BinaryExpression expr) + { + BinaryExpressionTypeFinder left = new BinaryExpressionTypeFinder(); + left.Visit(expr.Left); + + if (left.Type == BinaryCriterionType.None) + return base.VisitBinary(expr); + + BinaryExpressionTypeFinder right = new BinaryExpressionTypeFinder(); + right.Visit(expr.Right); + + if (right.Type == BinaryCriterionType.None) + return base.VisitBinary(expr); + + + if (right.Type == BinaryCriterionType.Property) + { + if (left.Type == BinaryCriterionType.Criteria + || left.Type == BinaryCriterionType.Value) + { + return Swap(expr); + } + } + else if (right.Type == BinaryCriterionType.Value) + { + if (left.Type == BinaryCriterionType.Criteria) + { + return Swap(expr); + } + } + + return expr; + } + + class BinaryExpressionTypeFinder : NHibernateExpressionVisitor + { + private bool _isNestedBinaryExpression; + private BinaryCriterionType _type; + + public BinaryCriterionType Type + { + get { return _type; } + private set + { + if (!_isNestedBinaryExpression) + _type = value; + } + } + + protected override Expression VisitBinary(BinaryExpression b) + { + _isNestedBinaryExpression = true; + return b; + } + + protected override Expression VisitMethodCall(MethodCallExpression expr) + { + Type = BinaryCriterionType.Criteria; + return expr; + } + + protected override Expression VisitConstant(ConstantExpression expr) + { + Type = BinaryCriterionType.Value; + return expr; + } + + protected override Expression VisitEntity(EntityExpression expr) + { + Type = BinaryCriterionType.Property; + return expr; + } + + protected override Expression VisitPropertyAccess(PropertyAccessExpression expr) + { + Type = BinaryCriterionType.Property; + return expr; + } + + protected override Expression VisitCollectionAccess(CollectionAccessExpression expr) + { + Type = BinaryCriterionType.Property; + return expr; + } + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/CollectionAliasVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/CollectionAliasVisitor.cs new file mode 100644 index 00000000000..2bcf2369848 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/CollectionAliasVisitor.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using NHibernate.Linq.Expressions; +using NHibernate.Linq.Util; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Assigns the appropriate aliases to a collection access. + /// + public class CollectionAliasVisitor : NHibernateExpressionVisitor + { + private IEnumerable _currentCollectionAliases; + + private string FindCollectionAlias(System.Type elementType) + { + if (_currentCollectionAliases == null) return null; + + foreach (ParameterExpression p in _currentCollectionAliases) + { + if (p.Type == elementType) + { + return p.Name; + } + } + + return null; + } + + protected override Expression VisitCollectionAccess(CollectionAccessExpression expr) + { + EntityExpression elementExpression = expr.ElementExpression; + if (elementExpression == null) + return expr; + + string alias = FindCollectionAlias(elementExpression.Type); + + if (String.IsNullOrEmpty(alias)) + return expr; + + elementExpression = new EntityExpression(elementExpression.AssociationPath, alias, elementExpression.Type, elementExpression.MetaData, elementExpression.Expression); + return new CollectionAccessExpression(expr.Name, expr.Type, expr.NHibernateType, expr.Expression, elementExpression); + } + + protected override Expression VisitMethodCall(MethodCallExpression expr) + { + if (expr.Arguments.Count > 1) + { + LambdaExpression lambda = LinqUtil.StripQuotes(expr.Arguments[1]) as LambdaExpression; + if (lambda != null) + { + _currentCollectionAliases = lambda.Parameters; + } + } + + return base.VisitMethodCall(expr); + } + + public static Expression AssignCollectionAccessAliases(Expression expr) + { + CollectionAliasVisitor visitor = new CollectionAliasVisitor(); + return visitor.Visit(expr); + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/EntityExpressionVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/EntityExpressionVisitor.cs new file mode 100644 index 00000000000..221a02f3692 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/EntityExpressionVisitor.cs @@ -0,0 +1,50 @@ +using System.Linq.Expressions; +using NHibernate.Linq.Expressions; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Retrieves the first (or root) instance of EntityExpression found in the given Expression. + /// + public class EntityExpressionVisitor : NHibernateExpressionVisitor + { + private readonly bool _findFirstEntity; + + public EntityExpression Expression { get; private set; } + + public EntityExpressionVisitor(bool findFirstEntity) + { + _findFirstEntity = findFirstEntity; + } + + protected override Expression VisitEntity(EntityExpression expr) + { + this.Expression = expr; + if (_findFirstEntity) return expr; + return base.VisitEntity(expr); + } + + protected override Expression VisitMethodCall(MethodCallExpression expr) + { + Visit(expr.Arguments[0]); + return expr; + } + + private static EntityExpression FindEntity(Expression expr, bool findFirst) + { + EntityExpressionVisitor visitor = new EntityExpressionVisitor(findFirst); + visitor.Visit(expr); + return visitor.Expression; + } + + public static EntityExpression FirstEntity(Expression expr) + { + return FindEntity(expr, true); + } + + public static EntityExpression RootEntity(Expression expr) + { + return FindEntity(expr, false); + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/Evaluator.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/Evaluator.cs new file mode 100644 index 00000000000..9bad33b2a17 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/Evaluator.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace NHibernate.Linq.Visitors +{ + public static class Evaluator + { + /// + /// Performs evaluation & replacement of independent sub-trees + /// + /// The root of the expression tree. + /// A function that decides whether a given expression node can be part of the local function. + /// A new tree with sub-trees evaluated and replaced. + public static Expression PartialEval(Expression expression, Func fnCanBeEvaluated) + { + return new SubtreeEvaluator(new Nominator(fnCanBeEvaluated).Nominate(expression)).Eval(expression); + } + + /// + /// Performs evaluation & replacement of independent sub-trees + /// + /// The root of the expression tree. + /// A new tree with sub-trees evaluated and replaced. + public static Expression PartialEval(Expression expression) + { + return PartialEval(expression, Evaluator.CanBeEvaluatedLocally); + } + + private static bool CanBeEvaluatedLocally(Expression expression) + { + if (expression.NodeType == ExpressionType.Constant) + { + return !(((ConstantExpression)expression).Value is IQueryable); + } + + return expression.NodeType != ExpressionType.Parameter; + } + + /// + /// Evaluates & replaces sub-trees when first candidate is reached (top-down) + /// + class SubtreeEvaluator : ExpressionVisitor + { + HashSet candidates; + + internal SubtreeEvaluator(HashSet candidates) + { + this.candidates = candidates; + } + + internal Expression Eval(Expression exp) + { + return this.Visit(exp); + } + + public override Expression Visit(Expression exp) + { + if (exp == null) + { + return null; + } + if (this.candidates.Contains(exp)) + { + return this.Evaluate(exp); + } + return base.Visit(exp); + } + + private Expression Evaluate(Expression e) + { + if (e.NodeType == ExpressionType.Constant) + return e; + + if (e.NodeType == ExpressionType.Lambda) + return e; + + LambdaExpression lambda = Expression.Lambda(e); + Delegate fn = lambda.Compile(); + return Expression.Constant(fn.DynamicInvoke(null), e.Type); + } + } + + /// + /// Performs bottom-up analysis to determine which nodes can possibly + /// be part of an evaluated sub-tree. + /// + class Nominator : ExpressionVisitor + { + Func fnCanBeEvaluated; + HashSet candidates; + bool cannotBeEvaluated; + + internal Nominator(Func fnCanBeEvaluated) + { + this.fnCanBeEvaluated = fnCanBeEvaluated; + } + + internal HashSet Nominate(Expression expression) + { + this.candidates = new HashSet(); + this.Visit(expression); + return this.candidates; + } + + public override Expression Visit(Expression expression) + { + if (expression != null) + { + bool saveCannotBeEvaluated = this.cannotBeEvaluated; + this.cannotBeEvaluated = false; + base.Visit(expression); + if (!this.cannotBeEvaluated) + { + if (this.fnCanBeEvaluated(expression)) + { + this.candidates.Add(expression); + } + else + { + this.cannotBeEvaluated = true; + } + } + this.cannotBeEvaluated |= saveCannotBeEvaluated; + } + return expression; + } + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/ExpressionVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/ExpressionVisitor.cs new file mode 100644 index 00000000000..ca06f853b6e --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/ExpressionVisitor.cs @@ -0,0 +1,394 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Linq.Expressions; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Provides virtual methods that can be used by subclasses to parse an expression tree. + /// + /// + /// This class actually already exists in the System.Core assembly...as an internal class. + /// I can only speculate as to why it is internal, but it is obviously much too dangerous + /// for anyone outside of Microsoft to be using... + /// + [DebuggerStepThrough, DebuggerNonUserCode] + public abstract class ExpressionVisitor + { + public virtual Expression Visit(Expression exp) + { + if (exp == null) return exp; + + switch (exp.NodeType) + { + case ExpressionType.Negate: + case ExpressionType.NegateChecked: + case ExpressionType.Not: + case ExpressionType.Convert: + case ExpressionType.ConvertChecked: + case ExpressionType.ArrayLength: + case ExpressionType.Quote: + case ExpressionType.TypeAs: + return VisitUnary((UnaryExpression)exp); + case ExpressionType.Add: + case ExpressionType.AddChecked: + case ExpressionType.Subtract: + case ExpressionType.SubtractChecked: + case ExpressionType.Multiply: + case ExpressionType.MultiplyChecked: + case ExpressionType.Divide: + case ExpressionType.Modulo: + case ExpressionType.And: + case ExpressionType.AndAlso: + case ExpressionType.Or: + case ExpressionType.OrElse: + case ExpressionType.LessThan: + case ExpressionType.LessThanOrEqual: + case ExpressionType.GreaterThan: + case ExpressionType.GreaterThanOrEqual: + case ExpressionType.Equal: + case ExpressionType.NotEqual: + case ExpressionType.Coalesce: + case ExpressionType.ArrayIndex: + case ExpressionType.RightShift: + case ExpressionType.LeftShift: + case ExpressionType.ExclusiveOr: + return VisitBinary((BinaryExpression)exp); + case ExpressionType.TypeIs: + return VisitTypeIs((TypeBinaryExpression)exp); + case ExpressionType.Conditional: + return VisitConditional((ConditionalExpression)exp); + case ExpressionType.Constant: + return VisitConstant((ConstantExpression)exp); + case ExpressionType.Parameter: + return VisitParameter((ParameterExpression)exp); + case ExpressionType.MemberAccess: + return VisitMemberAccess((MemberExpression)exp); + case ExpressionType.Call: + return VisitMethodCall((MethodCallExpression)exp); + case ExpressionType.Lambda: + return VisitLambda((LambdaExpression)exp); + case ExpressionType.New: + return VisitNew((NewExpression)exp); + case ExpressionType.NewArrayInit: + case ExpressionType.NewArrayBounds: + return VisitNewArray((NewArrayExpression)exp); + case ExpressionType.Invoke: + return VisitInvocation((InvocationExpression)exp); + case ExpressionType.MemberInit: + return VisitMemberInit((MemberInitExpression)exp); + case ExpressionType.ListInit: + return VisitListInit((ListInitExpression)exp); + default: + throw new NotSupportedException(String.Format("Unhandled expression type: '{0}'", exp.NodeType)); + } + } + + protected virtual MemberBinding VisitBinding(MemberBinding binding) + { + switch (binding.BindingType) + { + case MemberBindingType.Assignment: + return VisitMemberAssignment((MemberAssignment)binding); + case MemberBindingType.MemberBinding: + return VisitMemberMemberBinding((MemberMemberBinding)binding); + case MemberBindingType.ListBinding: + return VisitMemberListBinding((MemberListBinding)binding); + default: + throw new NotSupportedException(string.Format("Unhandled binding type '{0}'", binding.BindingType)); + } + } + + protected virtual ElementInit VisitElementInitializer(ElementInit initializer) + { + ReadOnlyCollection arguments = VisitList(initializer.Arguments); + if (arguments != initializer.Arguments) + { + return Expression.ElementInit(initializer.AddMethod, arguments); + } + return initializer; + } + + protected virtual Expression VisitUnary(UnaryExpression u) + { + Expression operand = Visit(u.Operand); + if (operand != u.Operand) + { + return Expression.MakeUnary(u.NodeType, operand, u.Type, u.Method); + } + return u; + } + + protected virtual Expression VisitBinary(BinaryExpression b) + { + Expression left = Visit(b.Left); + Expression right = Visit(b.Right); + Expression conversion = Visit(b.Conversion); + + if (left != b.Left || right != b.Right || conversion != b.Conversion) + { + if (b.NodeType == ExpressionType.Coalesce && b.Conversion != null) + return Expression.Coalesce(left, right, conversion as LambdaExpression); + else + return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method); + } + return b; + } + + protected virtual Expression VisitTypeIs(TypeBinaryExpression b) + { + Expression expr = Visit(b.Expression); + if (expr != b.Expression) + { + return Expression.TypeIs(expr, b.TypeOperand); + } + return b; + } + + protected virtual Expression VisitConstant(ConstantExpression c) + { + return c; + } + + protected virtual Expression VisitConditional(ConditionalExpression c) + { + Expression test = Visit(c.Test); + Expression ifTrue = Visit(c.IfTrue); + Expression ifFalse = Visit(c.IfFalse); + + if (test != c.Test || ifTrue != c.IfTrue || ifFalse != c.IfFalse) + { + return Expression.Condition(test, ifTrue, ifFalse); + } + + return c; + } + + protected virtual Expression VisitParameter(ParameterExpression p) + { + return p; + } + + protected virtual Expression VisitMemberAccess(MemberExpression m) + { + Expression exp = Visit(m.Expression); + if (exp != m.Expression) + { + return Expression.MakeMemberAccess(exp, m.Member); + } + return m; + } + + protected virtual Expression VisitMethodCall(MethodCallExpression m) + { + Expression obj = Visit(m.Object); + IEnumerable args = VisitList(m.Arguments); + + if (obj != m.Object || args != m.Arguments) + { + return Expression.Call(obj, m.Method, args); + } + + return m; + } + + protected virtual ReadOnlyCollection VisitList(ReadOnlyCollection original) + { + List list = null; + for (int i = 0, n = original.Count; i < n; i++) + { + Expression p = Visit(original[i]); + if (list != null) + { + list.Add(p); + } + else if (p != original[i]) + { + list = new List(n); + for (int j = 0; j < i; j++) + { + list.Add(original[j]); + } + list.Add(p); + } + } + + if (list != null) + return list.AsReadOnly(); + + return original; + } + + protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment assignment) + { + Expression e = Visit(assignment.Expression); + + if (e != assignment.Expression) + { + return Expression.Bind(assignment.Member, e); + } + + return assignment; + } + + protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding) + { + IEnumerable bindings = VisitBindingList(binding.Bindings); + + if (bindings != binding.Bindings) + { + return Expression.MemberBind(binding.Member, bindings); + } + + return binding; + } + + protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding) + { + IEnumerable initializers = VisitElementInitializerList(binding.Initializers); + + if (initializers != binding.Initializers) + { + return Expression.ListBind(binding.Member, initializers); + } + return binding; + } + + protected virtual IEnumerable VisitBindingList(ReadOnlyCollection original) + { + List list = null; + for (int i = 0, n = original.Count; i < n; i++) + { + MemberBinding b = VisitBinding(original[i]); + if (list != null) + { + list.Add(b); + } + else if (b != original[i]) + { + list = new List(n); + for (int j = 0; j < i; j++) + { + list.Add(original[j]); + } + list.Add(b); + } + } + + if (list != null) + return list; + + return original; + } + + protected virtual IEnumerable VisitElementInitializerList(ReadOnlyCollection original) + { + List list = null; + for (int i = 0, n = original.Count; i < n; i++) + { + ElementInit init = VisitElementInitializer(original[i]); + if (list != null) + { + list.Add(init); + } + else if (init != original[i]) + { + list = new List(n); + for (int j = 0; j < i; j++) + { + list.Add(original[j]); + } + list.Add(init); + } + } + + if (list != null) + return list; + + return original; + } + + protected virtual Expression VisitLambda(LambdaExpression lambda) + { + Expression body = Visit(lambda.Body); + if (body != lambda.Body) + { + return Expression.Lambda(lambda.Type, body, lambda.Parameters); + } + return lambda; + } + + protected virtual NewExpression VisitNew(NewExpression nex) + { + IEnumerable args = VisitList(nex.Arguments); + if (args != nex.Arguments) + { + if (nex.Members != null) + return Expression.New(nex.Constructor, args, nex.Members); + else + return Expression.New(nex.Constructor, args); + } + + return nex; + } + + protected virtual Expression VisitMemberInit(MemberInitExpression init) + { + NewExpression n = VisitNew(init.NewExpression); + IEnumerable bindings = VisitBindingList(init.Bindings); + + if (n != init.NewExpression || bindings != init.Bindings) + { + return Expression.MemberInit(n, bindings); + } + + return init; + } + + protected virtual Expression VisitListInit(ListInitExpression init) + { + NewExpression n = VisitNew(init.NewExpression); + IEnumerable initializers = VisitElementInitializerList(init.Initializers); + + if (n != init.NewExpression || initializers != init.Initializers) + { + return Expression.ListInit(n, initializers); + } + + return init; + } + + protected virtual Expression VisitNewArray(NewArrayExpression na) + { + IEnumerable exprs = VisitList(na.Expressions); + if (exprs != na.Expressions) + { + if (na.NodeType == ExpressionType.NewArrayInit) + { + return Expression.NewArrayInit(na.Type.GetElementType(), exprs); + } + else + { + return Expression.NewArrayBounds(na.Type.GetElementType(), exprs); + } + } + + return na; + } + + protected virtual Expression VisitInvocation(InvocationExpression iv) + { + IEnumerable args = VisitList(iv.Arguments); + Expression expr = Visit(iv.Expression); + + if (args != iv.Arguments || expr != iv.Expression) + { + return Expression.Invoke(expr, args); + } + + return iv; + } + } +} \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/GroupingArgumentsVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/GroupingArgumentsVisitor.cs new file mode 100644 index 00000000000..9058b4d9645 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/GroupingArgumentsVisitor.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using NHibernate.Criterion; +using NHibernate.Linq.Expressions; +using Expression = System.Linq.Expressions.Expression; +using NHProjections = NHibernate.Criterion.Projections; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Visits an expression tree providing the appropriate projections for grouping arguments. + /// + public class GroupingArgumentsVisitor : NHibernateExpressionVisitor + { + private readonly ICriteria _rootCriteria; + private readonly List _projections = new List(); + + public IProjection Projection + { + get + { + if (_projections.Count == 0) + return null; + + if (_projections.Count == 1) + return _projections[0]; + + ProjectionList list = NHProjections.ProjectionList(); + foreach (var projection in _projections) + list.Add(projection); + + return list; + } + } + + public GroupingArgumentsVisitor(ICriteria rootCriteria) + { + _rootCriteria = rootCriteria; + } + + protected override Expression VisitPropertyAccess(PropertyAccessExpression expr) + { + string name = MemberNameVisitor.GetMemberName(_rootCriteria, expr); + _projections.Add(NHProjections.GroupProperty(name)); + + return expr; + } + + protected override Expression VisitCollectionAccess(CollectionAccessExpression expr) + { + return VisitPropertyAccess(expr); + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/ImmediateResultsVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/ImmediateResultsVisitor.cs new file mode 100644 index 00000000000..c3f62b2490d --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/ImmediateResultsVisitor.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using NHibernate.Criterion; +using NHibernate.Linq.Util; +using LinqExpression = System.Linq.Expressions.Expression; + +namespace NHibernate.Linq.Visitors +{ + public interface IImmediateResultsVisitor + { + object GetResults(MethodCallExpression expr); + } + + /// + /// Visits any expression calls that require immediate results. + /// + public class ImmediateResultsVisitor : NHibernateExpressionVisitor, IImmediateResultsVisitor + { + private readonly ISession session; + private readonly ICriteria rootCriteria; + private T results; + + public ImmediateResultsVisitor(ISession session, ICriteria rootCriteria) + { + this.session = session; + this.rootCriteria = rootCriteria; + } + + public object GetResults(MethodCallExpression expr) + { + Visit(expr); + return results; + } + + protected override LinqExpression VisitMethodCall(MethodCallExpression call) + { + switch (call.Method.Name) + { + case "First": + results = HandleFirstCall(call); + break; + case "FirstOrDefault": + results = HandleFirstOrDefaultCall(call); + break; + case "Single": + results = HandleSingleCall(call); + break; + case "SingleOrDefault": + results = HandleSingleOrDefaultCall(call); + break; + case "Aggregate": + results = HandleAggregateCallback(call); + break; + case "Average": + case "Count": + case "LongCount": + case "Max": + case "Min": + case "Sum": + rootCriteria.ClearOrders(); + results = HandleAggregateCall(call); + break; + case "Any": + results = HandleAnyCall(call); + break; + default: + throw new NotImplementedException("The method " + call.Method.Name + " is not implemented."); + } + + return call; + } + + private T HandleFirstCall(MethodCallExpression call) + { + return GetElementList(call, 1).First(); + } + + private T HandleFirstOrDefaultCall(MethodCallExpression call) + { + return GetElementList(call, 1).FirstOrDefault(); + } + + private T HandleSingleCall(MethodCallExpression call) + { + return GetElementList(call, 2).Single(); + } + + private T HandleSingleOrDefaultCall(MethodCallExpression call) + { + return GetElementList(call, 2).SingleOrDefault(); + } + + private IList GetElementList(MethodCallExpression call, int count) + { + if (call.Arguments.Count > 1) + rootCriteria.Add(WhereArgumentsVisitor.GetCriterion(rootCriteria, session, call.Arguments[1])); + + return rootCriteria.SetFirstResult(0).SetMaxResults(count).List(); + } + + private T HandleAggregateCallback(MethodCallExpression call) + { + LambdaExpression lambda = (LambdaExpression)LinqUtil.StripQuotes(call.Arguments[call.Arguments.Count - 1]); + System.Type resultType = lambda.Parameters[1].Type; + + IList list = rootCriteria.List(); + MethodInfo castMethod = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(resultType); + IEnumerable enumerable = (IEnumerable)castMethod.Invoke(null, new object[] { list }); + + if (call.Arguments.Count == 2) + { + return (T)call.Method.Invoke(null, new object[] + { + enumerable.AsQueryable(), + lambda + }); + } + else if (call.Arguments.Count == 3) + { + return (T)call.Method.Invoke(null, new[] + { + enumerable.AsQueryable(), + ((ConstantExpression)call.Arguments[1]).Value, + lambda + }); + } + else if (call.Arguments.Count == 4) + { + return (T)call.Method.Invoke(null, new[] + { + enumerable.AsQueryable(), + ((ConstantExpression)call.Arguments[1]).Value, + LinqUtil.StripQuotes(call.Arguments[2]), + lambda + }); + } + + throw new ArgumentException("Invalid number of arguments passed to the Aggregate method."); + } + + private T HandleAggregateCall(MethodCallExpression call) + { + var visitor = new SelectArgumentsVisitor(rootCriteria, session); + visitor.Visit(call); + + T value = default(T); + if (visitor.Projection != null) + { + object result = rootCriteria.SetProjection(visitor.Projection).UniqueResult(); + if (result != null) + { + value = (T)LinqUtil.ChangeType(result, typeof(T)); + } + } + + return value; + } + + private T HandleAnyCall(MethodCallExpression call) + { + rootCriteria.SetProjection(Projections.RowCount()); + + if (call.Arguments.Count > 1) + rootCriteria.Add(WhereArgumentsVisitor.GetCriterion(rootCriteria, session, call.Arguments[1])); + + int count = (int)rootCriteria.UniqueResult(); + + //HACK: the Any method always returns bool - maybe need to make this class non-generic + return (T)(object)(count > 0); + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/InheritanceVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/InheritanceVisitor.cs new file mode 100644 index 00000000000..ecc1ce17817 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/InheritanceVisitor.cs @@ -0,0 +1,26 @@ +using System.Linq.Expressions; +using NHibernate.Linq.Expressions; + +namespace NHibernate.Linq.Visitors +{ + public class InheritanceVisitor : NHibernateExpressionVisitor + { + private System.Type castedType; + + protected override Expression VisitQuerySource(QuerySourceExpression expr) + { + if (castedType != null) + return new QuerySourceExpression(expr.Alias, expr.Query, castedType); + return base.VisitQuerySource(expr); + } + + protected override Expression VisitMethodCall(MethodCallExpression m) + { + //this is a naive implementation and will not work for any OfType calls not called on root entity + if (m.Method.Name == "OfType") + this.castedType = m.Method.GetGenericArguments()[0]; + + return base.VisitMethodCall(m); + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/MemberNameVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/MemberNameVisitor.cs new file mode 100644 index 00000000000..cc1cf5de98e --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/MemberNameVisitor.cs @@ -0,0 +1,153 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using NHibernate.Linq.Expressions; +using NHibernate.Linq.Util; +using NHibernate.SqlCommand; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Visits an expression providing the member name being accessed based on the EntityExpressions and + /// PropertyAccessExpressions in the expression tree. Any entity associations encountered are added + /// as subcriteria to the query. + /// + public class MemberNameVisitor : NHibernateExpressionVisitor + { + private readonly ICriteria rootCriteria; + private readonly bool createCriteriaForCollections; + private ICriteria currentCriteria; + private Expression currentExpression; + private StringBuilder memberNameBuilder; + private string currentAssociationPath; + private bool isQueringEntity; + + public string MemberName + { + get + { + if (isQueringEntity || memberNameBuilder.Length < 1) + return currentAssociationPath; + string memberName = memberNameBuilder.ToString(); + return memberName.Substring(0, memberName.Length - 1); //remove the last "." + } + } + + public ICriteria CurrentCriteria + { + get { return currentCriteria; } + } + + public Expression CurrentExpression + { + get { return currentExpression; } + } + + public MemberNameVisitor(ICriteria criteria) + : this(criteria, false) { } + + public MemberNameVisitor(ICriteria criteria, bool createCriteriaForCollections) + { + this.rootCriteria = this.currentCriteria = criteria; + this.createCriteriaForCollections = createCriteriaForCollections; + this.memberNameBuilder = new StringBuilder(); + } + + private void ResetMemberName(string name) + { + memberNameBuilder = new StringBuilder(); + memberNameBuilder.Append(name); + } + + private ICriteria EnsureCriteria(string associationPath, string alias) + { + ICriteria criteria; + if ((criteria = currentCriteria.GetCriteriaByAlias(alias)) == null) + { + criteria = currentCriteria.CreateCriteria(associationPath, alias, JoinType.LeftOuterJoin); + } + return criteria; + } + + private bool IsRootEntity(EntityExpression expr) + { + var nhExpression = expr.Expression as NHibernateExpression; + + if (nhExpression != null) + return false; + + if (expr.Type != rootCriteria.GetRootType()) + return false; + + return true; + } + + protected override Expression VisitEntity(EntityExpression expr) + { + expr = (EntityExpression)base.VisitEntity(expr); + + if (currentCriteria.GetCriteriaByAlias(expr.Alias) != null || !IsRootEntity(expr)) + { + if (!String.IsNullOrEmpty(expr.AssociationPath)) + currentCriteria = EnsureCriteria(expr.AssociationPath, expr.Alias); + + ResetMemberName(expr.Alias + "."); + } + currentAssociationPath = expr.AssociationPath; + currentExpression = expr; + isQueringEntity = true; + + return expr; + } + + protected override Expression VisitPropertyAccess(PropertyAccessExpression expr) + { + expr = (PropertyAccessExpression)base.VisitPropertyAccess(expr); + memberNameBuilder.Append(expr.Name + "."); + + currentExpression = expr; + isQueringEntity = false; + + return expr; + } + + protected override Expression VisitCollectionAccess(CollectionAccessExpression expr) + { + expr = (CollectionAccessExpression)base.VisitCollectionAccess(expr); + //memberNameBuilder.Append(expr.Name + "."); + ResetMemberName(expr.Name + "."); + currentExpression = expr; + + if (createCriteriaForCollections) + { + if (expr.ElementExpression != null) + { + currentCriteria = EnsureCriteria(expr.Name, expr.ElementExpression.Alias); + } + } + + isQueringEntity = false; + + return expr; + } + + protected override Expression VisitMethodCall(MethodCallExpression expr) + { + Visit(expr.Arguments[0]); + return expr; + } + + public static string GetMemberName(ICriteria rootCriteria, Expression expr) + { + MemberNameVisitor visitor = new MemberNameVisitor(rootCriteria); + visitor.Visit(expr); + return visitor.MemberName; + } + + public static string GetLastMemberName(ICriteria rootCriteria, Expression expr) + { + return GetMemberName(rootCriteria, expr).Split('.').Last(); + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/NHibernateExpressionVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/NHibernateExpressionVisitor.cs new file mode 100644 index 00000000000..881a19e1688 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/NHibernateExpressionVisitor.cs @@ -0,0 +1,68 @@ +using System.Diagnostics; +using System.Linq.Expressions; +using NHibernate.Linq.Expressions; + +namespace NHibernate.Linq.Visitors +{ + /// + /// NHibernate-specific base expression visitor. + /// + [DebuggerStepThrough, DebuggerNonUserCode] + public class NHibernateExpressionVisitor : ExpressionVisitor + { + public override Expression Visit(Expression exp) + { + if (exp == null) return null; + + switch ((NHibernateExpressionType)exp.NodeType) + { + case NHibernateExpressionType.QuerySource: + return VisitQuerySource((QuerySourceExpression)exp); + case NHibernateExpressionType.RootEntity: + case NHibernateExpressionType.Entity: + return VisitEntity((EntityExpression)exp); + case NHibernateExpressionType.PropertyAccess: + return VisitPropertyAccess((PropertyAccessExpression)exp); + case NHibernateExpressionType.CollectionAccess: + return VisitCollectionAccess((CollectionAccessExpression)exp); + default: + return base.Visit(exp); + } + } + + protected virtual Expression VisitQuerySource(QuerySourceExpression expr) + { + return expr; + } + + protected virtual Expression VisitEntity(EntityExpression expr) + { + Expression e = Visit(expr.Expression); + if (e != expr.Expression) + { + return new EntityExpression(expr.AssociationPath, expr.Alias, expr.Type, expr.MetaData, e); + } + return expr; + } + + protected virtual Expression VisitPropertyAccess(PropertyAccessExpression expr) + { + EntityExpression e = (EntityExpression)Visit(expr.Expression); + if (e != expr.Expression) + { + return new PropertyAccessExpression(expr.Name, expr.Type, expr.NHibernateType, e); + } + return expr; + } + + protected virtual Expression VisitCollectionAccess(CollectionAccessExpression expr) + { + EntityExpression e = (EntityExpression)Visit(expr.Expression); + if (e != expr.Expression) + { + return new CollectionAccessExpression(expr.Name, expr.Type, expr.NHibernateType, e, expr.ElementExpression); + } + return expr; + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/NHibernateQueryTranslator.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/NHibernateQueryTranslator.cs new file mode 100644 index 00000000000..a1bab5f934f --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/NHibernateQueryTranslator.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq.Expressions; +using NHibernate.Criterion; +using NHibernate.Linq.Expressions; +using NHibernate.Linq.Util; +using LinqExpression = System.Linq.Expressions.Expression; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Translates a Linq Expression into an NHibernate ICriteria object. + /// + public class NHibernateQueryTranslator : NHibernateExpressionVisitor + { + private readonly ISession session; + private readonly string entityName; + private ICriteria rootCriteria; + private QueryOptions options; + + public NHibernateQueryTranslator(ISession session) + { + this.session = session; + } + public NHibernateQueryTranslator(ISession session,string entityName) + { + this.session = session; + this.entityName = entityName; + } + + public virtual object Translate(LinqExpression expression, QueryOptions queryOptions) + { + this.rootCriteria = null; + this.options = queryOptions; + + Visit(expression); //ensure criteria + + var visitor = new RootVisitor(rootCriteria, session, true); + visitor.Visit(expression); + return visitor.Results; + } + + protected override LinqExpression VisitQuerySource(QuerySourceExpression expr) + { + if (rootCriteria == null) + { + if(!string.IsNullOrEmpty(this.entityName)) + rootCriteria = session.CreateCriteria(entityName, expr.Alias); + else + rootCriteria = session.CreateCriteria(expr.ElementType, expr.Alias); + options.Execute(rootCriteria); + } + return expr; + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/PropertyToMethodVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/PropertyToMethodVisitor.cs new file mode 100644 index 00000000000..25b340b72b5 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/PropertyToMethodVisitor.cs @@ -0,0 +1,46 @@ +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using NHibernate.Linq.Expressions; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Converts calls to an IEnumerable.Count property to IEnumerable.Count() extension method. + /// + public class PropertyToMethodVisitor : NHibernateExpressionVisitor + { + private MethodInfo GetCountMethod(System.Type elementType) + { + //this should work, but it doesn't... + //System.Type genericEnumerableType = typeof(IEnumerable<>).MakeGenericType(elementType); + //return typeof(Enumerable).GetMethod("Count", new System.Type[] { genericEnumerableType }); + + var method = typeof(Enumerable).GetMethods() + .Where(m => m.Name == "Count" && m.GetParameters().Count() == 1).First(); + return method.MakeGenericMethod(elementType); + } + + private Expression CastIfNecessary(CollectionAccessExpression expr) + { + if (expr.Type.IsGenericType) + return expr; + + MethodInfo method = typeof(Enumerable).GetMethod("Cast") + .MakeGenericMethod(expr.ElementExpression.Type); + + return Expression.Call(method, expr); + } + + protected override Expression VisitMemberAccess(MemberExpression m) + { + CollectionAccessExpression parent = m.Expression as CollectionAccessExpression; + if (parent != null && m.Member.Name == "Count") + { + MethodInfo method = GetCountMethod(parent.ElementExpression.Type); + return Expression.Call(method, CastIfNecessary(parent)); + } + return base.VisitMemberAccess(m); + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/RootVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/RootVisitor.cs new file mode 100644 index 00000000000..d1f4ad84958 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/RootVisitor.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq.Expressions; +using NHibernate.Criterion; +using NHibernate.Linq.Expressions; +using NHibernate.Linq.Util; +using LinqExpression = System.Linq.Expressions.Expression; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Translates a Linq Expression into an NHibernate ICriteria object. + /// + public class RootVisitor : NHibernateExpressionVisitor + { + private readonly ICriteria rootCriteria; + private readonly ISession session; + private readonly bool isAtRoot; + private object results; + private bool hasResults; + + public object Results + { + get + { + if (hasResults) + return results; + return rootCriteria; + } + } + + public RootVisitor(ICriteria rootCriteria, ISession session, bool isAtRoot) + { + this.rootCriteria = rootCriteria; + this.session = session; + this.isAtRoot = isAtRoot; + } + + protected override LinqExpression VisitMethodCall(MethodCallExpression expr) + { + Visit(expr.Arguments[0]); + + switch (expr.Method.Name) + { + case "Where": + HandleWhereCall(expr); + break; + case "Select": + HandleSelectCall(expr); + break; + case "OrderBy": + case "ThenBy": + HandleOrderByCall(expr); + break; + case "OrderByDescending": + case "ThenByDescending": + HandleOrderByDescendingCall(expr); + break; + case "Take": + HandleTakeCall(expr); + break; + case "Skip": + HandleSkipCall(expr); + break; + case "Distinct": + HandleDistinctCall(expr); + break; + case "GroupBy": + HandleGroupByCall(expr); + break; + case "SelectMany": + HandleSelectManyCall(expr); + break; + case "OfType": + case "Cast": + //ignore OfType calls -- handled by InheritanceVisitor + break; + case "First": + case "FirstOrDefault": + case "Single": + case "SingleOrDefault": + case "Aggregate": + case "Average": + case "Count": + case "LongCount": + case "Max": + case "Min": + case "Sum": + case "Any": + if (isAtRoot) + HandleImmediateResultsCall(expr); + else + HandleSelectMethodCall(expr); + break; + default: + throw new NotImplementedException("The method " + expr.Method.Name + " is not implemented."); + } + + return expr; + } + + private void HandleWhereCall(MethodCallExpression call) + { + IEnumerable criterion = WhereArgumentsVisitor.GetCriterion(rootCriteria, session, call.Arguments[1]); + rootCriteria.Add(criterion); + } + + private void HandleSelectCall(MethodCallExpression call) + { + var lambda = (LambdaExpression)LinqUtil.StripQuotes(call.Arguments[1]); + + var visitor = new SelectArgumentsVisitor(rootCriteria, session); + visitor.Visit(lambda.Body); + + rootCriteria.SetProjectionIfNotNull(visitor.Projection); + rootCriteria.SetResultTransformerIfNotNull(visitor.Transformer); + } + + private void HandleOrderByCall(MethodCallExpression call) + { + LinqExpression expr = ((UnaryExpression)call.Arguments[1]).Operand; + + string name = MemberNameVisitor.GetMemberName(rootCriteria, expr); + rootCriteria.AddOrder(Order.Asc(name)); + } + + private void HandleOrderByDescendingCall(MethodCallExpression call) + { + LinqExpression expr = ((UnaryExpression)call.Arguments[1]).Operand; + + string name = MemberNameVisitor.GetMemberName(rootCriteria, expr); + rootCriteria.AddOrder(Order.Desc(name)); + } + + private void HandleTakeCall(MethodCallExpression call) + { + var count = (int)((ConstantExpression)call.Arguments[1]).Value; + rootCriteria.SetMaxResults(count); + } + + private void HandleSkipCall(MethodCallExpression call) + { + var index = (int)((ConstantExpression)call.Arguments[1]).Value; + rootCriteria.SetFirstResult(index); + } + + private void HandleDistinctCall(MethodCallExpression call) + { + var projection = rootCriteria.GetProjection() as PropertyProjection; + if (projection != null) + { + rootCriteria.SetProjection( + Projections.Distinct( + Projections.Property(projection.PropertyName))); + } + } + + private void HandleGroupByCall(MethodCallExpression call) + { + var visitor = new GroupingArgumentsVisitor(rootCriteria); + visitor.Visit(call.Arguments[1]); + rootCriteria.SetProjectionIfNotNull(visitor.Projection); + } + + private void HandleSelectManyCall(MethodCallExpression call) + { + //get the association path for the joined entity + var collectionSelector = (LambdaExpression)LinqUtil.StripQuotes(call.Arguments[1]); + + LambdaExpression resultSelector = null; + if (call.Arguments.Count == 3) + { + resultSelector = (LambdaExpression)LinqUtil.StripQuotes(call.Arguments[2]); + string alias = resultSelector.Parameters[1].Name; + + var visitor = new SelectManyVisitor(rootCriteria, alias); + visitor.Visit(collectionSelector.Body); + } + + if (resultSelector != null) + { + //visit the result selector expression after the alias for the association has been created + var resultSelectorVisitor = new SelectArgumentsVisitor(rootCriteria, session); + resultSelectorVisitor.Visit(resultSelector.Body); + + rootCriteria.SetProjectionIfNotNull(resultSelectorVisitor.Projection); + rootCriteria.SetResultTransformerIfNotNull(resultSelectorVisitor.Transformer); + } + } + + private void HandleImmediateResultsCall(MethodCallExpression call) + { + System.Type resultType = call.Method.ReturnType; + System.Type visitorType = typeof(ImmediateResultsVisitor<>) + .MakeGenericType(resultType); + + var visitor = (IImmediateResultsVisitor)Activator + .CreateInstance(visitorType, session, rootCriteria); + + hasResults = true; + results = visitor.GetResults(call); + } + + private void HandleSelectMethodCall(MethodCallExpression call) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/SelectArgumentsVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/SelectArgumentsVisitor.cs new file mode 100644 index 00000000000..48f4e542017 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/SelectArgumentsVisitor.cs @@ -0,0 +1,361 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using NHibernate.Criterion; +using NHibernate.Dialect.Function; +using NHibernate.Linq.Expressions; +using NHibernate.Linq.Transform; +using NHibernate.Linq.Util; +using NHibernate.Transform; +using NHibernate.Type; +using Expression = System.Linq.Expressions.Expression; +using NHProjections = NHibernate.Criterion.Projections; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Provides the appropriate NHibernate selection projections and/or IResultTransformers + /// based on a given expression tree. + /// + public class SelectArgumentsVisitor : NHibernateExpressionVisitor + { + #region Fields & Properties + + private static readonly ISQLFunction arithmaticAddition = new VarArgsSQLFunction("(", "+", ")"); + private static readonly ISQLFunction arithmaticDivide = new VarArgsSQLFunction("(", "/", ")"); + private static readonly ISQLFunction arithmaticMultiply = new VarArgsSQLFunction("(", "*", ")"); + private static readonly ISQLFunction arithmaticSubstract = new VarArgsSQLFunction("(", "-", ")"); + + private readonly ICriteria _rootCriteria; + private readonly ISession _session; + private readonly List _projections; + private IResultTransformer _transformer; + private ICriteriaQuery _criteriaQuery; + + public IProjection Projection + { + get + { + if (_projections.Count == 0) + return null; + + if (_projections.Count == 1) + return _projections[0]; + + ProjectionList list = NHProjections.ProjectionList(); + foreach (var projection in _projections) + list.Add(projection); + + return list; + } + } + + public IResultTransformer Transformer + { + get { return _transformer; } + } + + private ICriteriaQuery CriteriaQuery + { + get + { + if (_criteriaQuery == null) + _criteriaQuery = _rootCriteria.GenerateCriteriaQuery(_session.SessionFactory, _rootCriteria.GetEntityOrClassName()); + return _criteriaQuery; + } + } + + #endregion + + public SelectArgumentsVisitor(ICriteria rootCriteria, ISession session) + { + _rootCriteria = rootCriteria; + _session = session; + _projections = new List(); + } + + public static bool SupportsMethod(string methodName) + { + return "Average".Equals(methodName) + || "Count".Equals(methodName) + || "LongCount".Equals(methodName) + || "Max".Equals(methodName) + || "Min".Equals(methodName) + || "Sum".Equals(methodName); + } + + protected override Expression VisitMethodCall(MethodCallExpression expr) + { + if (WhereArgumentsVisitor.SupportsMethod(expr.Method.Name)) + return VisitCriterionExpression(expr); + + //TODO: this needs to be refactored... + //create any collection subcriteria and get the collection access expression + MemberNameVisitor memberVisitor = new MemberNameVisitor(_rootCriteria, true); + memberVisitor.Visit(expr.Arguments[0]); + CollectionAccessExpression collectionExpr = (CollectionAccessExpression)memberVisitor.CurrentExpression; + + string propertyName = null; + IProjection projection = null; + PropertyProjection currentProjection; + + if (expr.Arguments.Count > 1) + { + propertyName = MemberNameVisitor.GetMemberName(_rootCriteria, expr.Arguments[1]); + } + else if ((currentProjection = _rootCriteria.GetProjection() as PropertyProjection) != null) + { + propertyName = currentProjection.PropertyName; + } + + switch (expr.Method.Name) + { + case "Average": + projection = NHProjections.Avg(propertyName); + break; + case "Count": + case "LongCount": + if (expr.Arguments.Count > 1) + _rootCriteria.Add(WhereArgumentsVisitor.GetCriterion(_rootCriteria, _session, expr.Arguments[1])); + + if (collectionExpr != null) + { + //get count on collection element's identifier property + propertyName = memberVisitor.MemberName + "." + collectionExpr.ElementExpression.MetaData.IdentifierPropertyName; + projection = NHProjections.Count(propertyName); + } + else + { + projection = NHProjections.RowCount(); + } + break; + case "Max": + projection = NHProjections.Max(propertyName); + break; + case "Min": + projection = NHProjections.Min(propertyName); + break; + case "Sum": + projection = NHProjections.Sum(propertyName); + break; + default: + throw new NotImplementedException("The method '" + expr.Method.Name + "' is not implemented."); + } + + _projections.Add(projection); + return expr; + } + + protected override Expression VisitConstant(ConstantExpression expr) + { + _projections.Add(new ConstantProjection(expr.Value)); + return expr; + } + + protected override NewExpression VisitNew(NewExpression expr) + { + NewExpression newExpr = base.VisitNew(expr); + _transformer = new TypeSafeConstructorMemberInitResultTransformer(expr); + + var aggregators = expr.Arguments.Where(arg => arg is MethodCallExpression && SupportsMethod(((MethodCallExpression)arg).Method.Name)); + if (aggregators.Any()) + { + foreach (var exp in expr.Arguments.Except(aggregators)) + { + string propertyName = MemberNameVisitor.GetMemberName(_rootCriteria, exp); + if (!String.IsNullOrEmpty(propertyName)) + { + _projections.Add(NHProjections.GroupProperty(propertyName)); + } + } + } + + return newExpr; + } + + protected override Expression VisitMemberInit(MemberInitExpression expr) + { + Expression newExpr = base.VisitMemberInit(expr); + _transformer = new TypeSafeConstructorMemberInitResultTransformer(expr); + return newExpr; + } + + protected override Expression VisitConditional(ConditionalExpression expr) + { + var visitorTrue = new SelectArgumentsVisitor(_rootCriteria, _session); + visitorTrue.Visit(expr.IfTrue); + + var visitorFalse = new SelectArgumentsVisitor(_rootCriteria, _session); + visitorFalse.Visit(expr.IfFalse); + + var visitorCondition = new WhereArgumentsVisitor(_rootCriteria, _session); + visitorCondition.Visit(expr.Test); + Conjunction conjunction = NHibernate.Criterion.Expression.Conjunction(); + foreach (var criterion in visitorCondition.CurrentCriterions) + { + conjunction.Add(criterion); + } + + _projections.Add( + NHibernate.Criterion.Projections + .Conditional(conjunction, + visitorTrue.Projection, + visitorFalse.Projection) + ); + + return expr; + } + + protected override Expression VisitBinary(BinaryExpression expr) + { + switch (expr.NodeType) + { + case ExpressionType.Add: + VisitAddExpression(expr); + break; + case ExpressionType.Divide: + VisitDivideExpression(expr); + break; + case ExpressionType.Multiply: + VisitMultiplyExpression(expr); + break; + case ExpressionType.Subtract: + VisitSubtractExpression(expr); + break; + default: + return VisitCriterionExpression(expr); + } + + return expr; + } + + private Expression VisitCriterionExpression(Expression expr) + { + IEnumerable criterion = WhereArgumentsVisitor.GetCriterion(_rootCriteria, _session, expr); + + if (criterion.Count() > 0) + { + Conjunction conjunction = new Conjunction(); + foreach (ICriterion crit in criterion) + { + conjunction.Add(crit); + } + + _projections.Add(Projections.Conditional( + conjunction, + Projections.Constant(true), + Projections.Constant(false)) + ); + } + + return expr; + } + + #region Arithmetic + + private void VisitAddExpression(BinaryExpression expr) + { + var leftVisitor = new SelectArgumentsVisitor(_rootCriteria, _session); + var rightVisitor = new SelectArgumentsVisitor(_rootCriteria, _session); + leftVisitor.Visit(expr.Left); + rightVisitor.Visit(expr.Right); + + var joinedProjections = new List(); + joinedProjections.AddRange(leftVisitor._projections); + joinedProjections.AddRange(rightVisitor._projections); + + IType[] types = joinedProjections[0].GetTypes(_rootCriteria, CriteriaQuery); + var useConcat = types[0] is AbstractStringType; + SqlFunctionProjection projection; + if (useConcat) + { + projection = new SqlFunctionProjection("concat", types[0], joinedProjections.ToArray()); + } + else + { + projection = new SqlFunctionProjection(arithmaticAddition, types[0], joinedProjections.ToArray()); + } + _projections.Add(projection); + } + + private void VisitMultiplyExpression(BinaryExpression expr) + { + VisitAritmaticOperation(expr, arithmaticMultiply); + } + + private void VisitSubtractExpression(BinaryExpression expr) + { + VisitAritmaticOperation(expr, arithmaticSubstract); + } + + private void VisitDivideExpression(BinaryExpression expr) + { + VisitAritmaticOperation(expr, arithmaticDivide); + } + + private void VisitAritmaticOperation(BinaryExpression expr, ISQLFunction arithmaticOperation) + { + var leftVisitor = new SelectArgumentsVisitor(_rootCriteria, _session); + var rightVisitor = new SelectArgumentsVisitor(_rootCriteria, _session); + leftVisitor.Visit(expr.Left); + rightVisitor.Visit(expr.Right); + + var joinedProjections = new List(); + joinedProjections.AddRange(leftVisitor._projections); + joinedProjections.AddRange(rightVisitor._projections); + var types = joinedProjections[0].GetTypes(_rootCriteria, CriteriaQuery); + var projection = new SqlFunctionProjection(arithmaticOperation, types[0], joinedProjections.ToArray()); + _projections.Add(projection); + } + + #endregion + + protected override Expression VisitUnary(UnaryExpression expr) + { + if (expr.NodeType == ExpressionType.Convert) + { + var visitor = new SelectArgumentsVisitor(_rootCriteria, _session); + visitor.Visit(expr.Operand); + + ProjectionList list = NHProjections.ProjectionList(); + foreach (IProjection proj in visitor._projections) + list.Add(proj); + + var projection = new CastProjection(NHibernateUtil.GuessType(expr.Type), list); + _projections.Add(projection); + } + + return expr; + } + + protected override Expression VisitEntity(EntityExpression expr) + { + if (_rootCriteria.GetCriteriaByAlias(expr.Alias) != null) + { + _transformer = new LinqJoinResultsTransformer(expr.Type); + } + + return expr; + } + + protected override Expression VisitMemberAccess(MemberExpression expr) + { + //this must be a grouping parameter member access + IProjection projection = _rootCriteria.GetProjection(); + if (projection != null && projection.IsGrouped) + { + _projections.Add(NHProjections.Alias(projection, expr.Member.Name)); + } + + return expr; + } + + protected override Expression VisitPropertyAccess(PropertyAccessExpression expr) + { + string memberName = MemberNameVisitor.GetMemberName(_rootCriteria, expr); + _projections.Add(NHProjections.Property(memberName)); + return expr; + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/SelectManyVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/SelectManyVisitor.cs new file mode 100644 index 00000000000..8b610ff9213 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/SelectManyVisitor.cs @@ -0,0 +1,36 @@ +using System.Linq.Expressions; +using NHibernate.Linq.Expressions; +using NHibernate.SqlCommand; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Adds the appropriate subcriteria to the query based on a SelectMany expression tree. + /// + public class SelectManyVisitor : NHibernateExpressionVisitor + { + private readonly ICriteria _rootCriteria; + private readonly string _alias; + + public SelectManyVisitor(ICriteria criteria, string alias) + { + _rootCriteria = criteria; + _alias = alias; + } + + protected override Expression VisitCollectionAccess(CollectionAccessExpression expr) + { + MemberNameVisitor visitor = new MemberNameVisitor(_rootCriteria, false); + visitor.Visit(expr.Expression); + + visitor.CurrentCriteria.CreateCriteria(expr.Name, _alias, JoinType.LeftOuterJoin); + return expr; + } + + protected override Expression VisitMethodCall(MethodCallExpression expr) + { + Visit(expr.Arguments[0]); + return expr; + } + } +} diff --git a/src/Libraries/NHibernate/NHibernate.Linq/Visitors/WhereArgumentsVisitor.cs b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/WhereArgumentsVisitor.cs new file mode 100644 index 00000000000..569d2980008 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/Visitors/WhereArgumentsVisitor.cs @@ -0,0 +1,370 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq.Expressions; +using NHibernate.Criterion; +using NHibernate.Linq.Expressions; +using NHibernate.Linq.Util; +using NHibernate.Persister.Entity; +using Expression = System.Linq.Expressions.Expression; + +namespace NHibernate.Linq.Visitors +{ + /// + /// Provides ICriterion for a query given a Linq expression tree. + /// + public class WhereArgumentsVisitor : NHibernateExpressionVisitor + { + private readonly Stack> criterionStack = new Stack>(); + private readonly ICriteria rootCriteria; + private readonly ISession session; + + public WhereArgumentsVisitor(ICriteria rootCriteria, ISession session) + { + criterionStack.Push(new List()); + this.rootCriteria = rootCriteria; + this.session = session; + } + + public static IEnumerable GetCriterion(ICriteria rootCriteria, ISession session, Expression expression) + { + var visitor = new WhereArgumentsVisitor(rootCriteria, session); + visitor.Visit(expression); + return visitor.CurrentCriterions; + } + + /// + /// Gets the current collection of objects. + /// + public IList CurrentCriterions + { + get { return criterionStack.Peek(); } + } + + public static bool SupportsMethod(string methodName) + { + return "Any".Equals(methodName) + || "StartsWith".Equals(methodName) + || "EndsWith".Equals(methodName) + || "Contains".Equals(methodName) + || "Equals".Equals(methodName); + } + + protected override Expression VisitConstant(ConstantExpression expr) + { + if (expr.Type == typeof(bool)) + { + bool value = (bool)expr.Value; + var falseCriteria = NHibernate.Criterion.Expression.Sql("1=0"); + var trueCriteria = NHibernate.Criterion.Expression.Sql("1=1"); + if (value) + { + this.CurrentCriterions.Add(trueCriteria); + } + else + { + this.CurrentCriterions.Add(falseCriteria); + } + + return expr; + } + + if (expr.Type.IsSubclassOf(typeof(Expression))) + return Visit(expr.Value as Expression); + + return base.VisitConstant(expr); + } + + protected override Expression VisitMethodCall(MethodCallExpression expr) + { + switch (expr.Method.Name) + { + case "Any": + CurrentCriterions.Add(GetExistsCriteria(expr)); + break; + case "StartsWith": + CurrentCriterions.Add(GetLikeCriteria(expr, MatchMode.Start)); + break; + case "EndsWith": + CurrentCriterions.Add(GetLikeCriteria(expr, MatchMode.End)); + break; + case "Contains": + if (expr.Object == null) + { + if (expr.Arguments[0] is ConstantExpression) + { + CurrentCriterions.Add(GetCollectionContainsCriteria(expr.Arguments[0], expr.Arguments[1])); + } + else if (expr.Arguments[0] is CollectionAccessExpression) + { + CurrentCriterions.Add(GetCollectionContainsCriteria((CollectionAccessExpression)expr.Arguments[0], expr.Arguments[1])); + } + else + { + //myArray.Contains(user.Name) + CurrentCriterions.Add(GetCollectionContainsCriteria(expr.Arguments[0], expr.Arguments[1])); + } + } + else if (expr.Object is ConstantExpression) + { + //myList.Contains(user.Name) + CurrentCriterions.Add(GetCollectionContainsCriteria(expr.Object, expr.Arguments[0])); + } + else if (expr.Object is CollectionAccessExpression) + { + //timesheet.Entries.Contains(entry) + CurrentCriterions.Add(GetCollectionContainsCriteria((CollectionAccessExpression)expr.Object, expr.Arguments[0])); + } + else + { + //user.Name.Contains(partialName) + CurrentCriterions.Add(GetLikeCriteria(expr, MatchMode.Anywhere)); + } + break; + case "Equals": + VisitBinaryCriterionExpression(Expression.Equal(expr.Object, expr.Arguments[0])); + break; + } + + return expr; + } + + protected override Expression VisitTypeIs(TypeBinaryExpression expr) + { + var visitor = new MemberNameVisitor(rootCriteria); + visitor.Visit(expr); + string memberName = visitor.MemberName + ".class"; + + var metaData = session.SessionFactory.GetClassMetadata(expr.TypeOperand); + if (metaData.HasSubclasses) + { + //make sure to include any subtypes + var disjunction = new Disjunction(); + foreach (string entityName in ((IEntityPersister)metaData).EntityMetamodel.SubclassEntityNames) + { + var metadata = session.SessionFactory.GetClassMetadata(entityName); + disjunction.Add(Property.ForName(memberName).Eq(metadata.MappedClass)); + } + visitor.CurrentCriteria.Add(disjunction); + } + else + { + visitor.CurrentCriteria.Add(Property.ForName(memberName).Eq(expr.TypeOperand)); + } + + return expr; + } + + protected override Expression VisitBinary(BinaryExpression expr) + { + switch (expr.NodeType) + { + case ExpressionType.AndAlso: + VisitAndAlsoExpression(expr); + break; + + case ExpressionType.OrElse: + VisitOrElseExpression(expr); + break; + + default: + VisitBinaryCriterionExpression(expr); + break; + } + + return expr; + } + + private void VisitAndAlsoExpression(BinaryExpression expr) + { + criterionStack.Push(new List()); + Visit(expr.Left); + Visit(expr.Right); + var ands = criterionStack.Pop(); + + var conjunction = new Conjunction(); + foreach (var crit in ands) + conjunction.Add(crit); + CurrentCriterions.Add(conjunction); + } + + private void VisitOrElseExpression(BinaryExpression expr) + { + criterionStack.Push(new List()); + Visit(expr.Left); + Visit(expr.Right); + IList ors = criterionStack.Pop(); + + var disjunction = new Disjunction(); + foreach (ICriterion crit in ors) + { + disjunction.Add(crit); + } + CurrentCriterions.Add(disjunction); + } + + private void VisitBinaryCriterionExpression(BinaryExpression expr) + { + ComparePropToValue comparePropToValue = null; + ComparePropToProp comparePropToProp = null; + CompareValueToCriteria compareValueToCriteria = null; + ComparePropToCriteria comparePropToCriteria = null; + + switch (expr.NodeType) + { + case ExpressionType.Equal: + comparePropToValue = (n, v) => (v != null) ? Restrictions.Eq(n, v) : Restrictions.IsNull(n); + comparePropToProp = Restrictions.EqProperty; + compareValueToCriteria = Subqueries.Eq; + comparePropToCriteria = Subqueries.PropertyEq; + break; + + case ExpressionType.GreaterThan: + comparePropToValue = Restrictions.Gt; + comparePropToProp = Restrictions.GtProperty; + compareValueToCriteria = Subqueries.Gt; + comparePropToCriteria = Subqueries.PropertyGt; + break; + + case ExpressionType.GreaterThanOrEqual: + comparePropToValue = Restrictions.Ge; + comparePropToProp = Restrictions.GeProperty; + compareValueToCriteria = Subqueries.Ge; + comparePropToCriteria = Subqueries.PropertyGe; + break; + + case ExpressionType.LessThan: + comparePropToValue = Restrictions.Lt; + comparePropToProp = Restrictions.LtProperty; + compareValueToCriteria = Subqueries.Lt; + comparePropToCriteria = Subqueries.PropertyLt; + break; + + case ExpressionType.LessThanOrEqual: + comparePropToValue = Restrictions.Le; + comparePropToProp = Restrictions.LeProperty; + compareValueToCriteria = Subqueries.Le; + comparePropToCriteria = Subqueries.PropertyLe; + break; + + case ExpressionType.NotEqual: + comparePropToValue = (n, v) => (v != null) ? Restrictions.Not(Restrictions.Eq(n, v)) : Restrictions.IsNotNull(n); + comparePropToProp = Restrictions.NotEqProperty; + compareValueToCriteria = Subqueries.Ne; + comparePropToCriteria = Subqueries.PropertyNe; + break; + } + + CurrentCriterions.Add( + BinaryCriterionVisitor.GetBinaryCriteria(rootCriteria, session, + expr, comparePropToValue, comparePropToProp, + compareValueToCriteria, comparePropToCriteria)); + } + + protected override Expression VisitUnary(UnaryExpression expr) + { + switch (expr.NodeType) + { + case ExpressionType.Quote: + Visit(expr.Operand); + break; + + case ExpressionType.Not: + VisitNotExpression(expr); + break; + } + + return expr; + } + + private void VisitNotExpression(UnaryExpression expr) + { + var criterions = GetCriterion(rootCriteria, session, expr.Operand); + + Conjunction conjunction = Restrictions.Conjunction(); + foreach (var criterion in criterions) + conjunction.Add(criterion); + + CurrentCriterions.Add(Restrictions.Not(conjunction)); + } + + protected override Expression VisitPropertyAccess(PropertyAccessExpression expr) + { + if (expr.Type == typeof(bool)) + { + string name = MemberNameVisitor.GetMemberName(rootCriteria, expr); + CurrentCriterions.Add(Restrictions.Eq(name, true)); + } + + return expr; + } + + private ICriterion GetExistsCriteria(MethodCallExpression expr) + { + EntityExpression rootEntity = EntityExpressionVisitor.FirstEntity(expr); + string propertyName = MemberNameVisitor.GetMemberName(rootCriteria, expr); + + DetachedCriteria query = DetachedCriteria.For(rootEntity.Type) + .SetProjection(Projections.Id()) + .Add(Restrictions.IsNotEmpty(propertyName)); + + if (expr.Arguments.Count > 1) + { + var arg = (LambdaExpression)LinqUtil.StripQuotes(expr.Arguments[1]); + string alias = arg.Parameters[0].Name; + + DetachedCriteria subquery = query.CreateCriteria(propertyName, alias); + + var temp = new WhereArgumentsVisitor(subquery.Adapt(session), session); + temp.Visit(arg.Body); + + foreach (ICriterion c in temp.CurrentCriterions) + { + subquery.Add(c); + } + } + + string identifierName = rootEntity.GetAliasedIdentifierPropertyName(); + return Subqueries.PropertyIn(identifierName, query); + } + + private ICriterion GetLikeCriteria(MethodCallExpression expr, MatchMode matchMode) + { + return Restrictions.Like(MemberNameVisitor.GetMemberName(rootCriteria, expr.Object), + String.Format("{0}", QueryUtil.GetExpressionValue(expr.Arguments[0])), + matchMode); + } + + private ICriterion GetCollectionContainsCriteria(CollectionAccessExpression arg, Expression containsExpression) + { + EntityExpression rootEntity = EntityExpressionVisitor.FirstEntity(arg); + + DetachedCriteria query = DetachedCriteria.For(rootEntity.Type) + .SetProjection(Projections.Id()); + + var visitor = new MemberNameVisitor(query.Adapt(session), true); + visitor.Visit(arg); + + //TODO: this won't work for collections of values + var containedEntity = QueryUtil.GetExpressionValue(containsExpression); + var collectionIdPropertyName = visitor.MemberName + "." + arg.ElementExpression.MetaData.IdentifierPropertyName; + var idValue = arg.ElementExpression.MetaData.GetIdentifier(containedEntity); + + query.Add(Restrictions.Eq(collectionIdPropertyName, idValue)); + + string identifierName = rootEntity.MetaData.IdentifierPropertyName; + return Subqueries.PropertyIn(identifierName, query); + } + + private ICriterion GetCollectionContainsCriteria(Expression list, Expression containedExpr) + { + var values = QueryUtil.GetExpressionValue(list) as ICollection; + + if (values == null) + throw new InvalidOperationException("Expression argument must be of type ICollection."); + + return Restrictions.In(MemberNameVisitor.GetMemberName(rootCriteria, containedExpr), + values); + } + } +} \ No newline at end of file diff --git a/src/Libraries/NHibernate/NHibernate.Linq/packages.config b/src/Libraries/NHibernate/NHibernate.Linq/packages.config new file mode 100644 index 00000000000..55205e415a1 --- /dev/null +++ b/src/Libraries/NHibernate/NHibernate.Linq/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/NuGet.config b/src/NuGet.config new file mode 100644 index 00000000000..04f49beabcf --- /dev/null +++ b/src/NuGet.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/Orchard.Azure.Tests/App.config b/src/Orchard.Azure.Tests/App.config index 391caa2724e..c6a416d39e3 100644 --- a/src/Orchard.Azure.Tests/App.config +++ b/src/Orchard.Azure.Tests/App.config @@ -7,7 +7,7 @@ - + @@ -21,15 +21,27 @@ - + - + - + + + + + + + + + + + + + diff --git a/src/Orchard.Azure.Tests/Orchard.Azure.Tests.csproj b/src/Orchard.Azure.Tests/Orchard.Azure.Tests.csproj index 0ffbf455e17..141e66a1723 100644 --- a/src/Orchard.Azure.Tests/Orchard.Azure.Tests.csproj +++ b/src/Orchard.Azure.Tests/Orchard.Azure.Tests.csproj @@ -10,7 +10,8 @@ Properties Orchard.Azure.Tests Orchard.Azure.Tests - v4.5.2 + v4.8 + 7.3 512 @@ -55,20 +56,23 @@ false + + ..\packages\log4net.2.0.12\lib\net45\log4net.dll + ..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll True - - ..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll + + ..\packages\Microsoft.Data.Edm.5.8.4\lib\net40\Microsoft.Data.Edm.dll True - - ..\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll + + ..\packages\Microsoft.Data.OData.5.8.4\lib\net40\Microsoft.Data.OData.dll True - - ..\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll + + ..\packages\Microsoft.Data.Services.Client.5.8.4\lib\net40\Microsoft.Data.Services.Client.dll True @@ -83,9 +87,8 @@ ..\packages\Moq.4.2.1510.2205\lib\NET40\Moq.dll True - - ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True + + ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll ..\packages\NUnit.2.5.10.11092\lib\nunit.framework.dll @@ -104,8 +107,8 @@ 3.5 - - ..\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll + + ..\packages\System.Spatial.5.8.4\lib\net40\System.Spatial.dll True @@ -128,7 +131,9 @@ Designer - + + Designer + diff --git a/src/Orchard.Azure.Tests/packages.config b/src/Orchard.Azure.Tests/packages.config index 1fc56c03260..33df3caece9 100644 --- a/src/Orchard.Azure.Tests/packages.config +++ b/src/Orchard.Azure.Tests/packages.config @@ -1,12 +1,13 @@  - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/src/Orchard.Core.Tests/App.config b/src/Orchard.Core.Tests/App.config index b04735a1b90..476eb41bdac 100644 --- a/src/Orchard.Core.Tests/App.config +++ b/src/Orchard.Core.Tests/App.config @@ -4,11 +4,11 @@ - + - + @@ -16,8 +16,16 @@ - + + + + + + + + + - \ No newline at end of file + diff --git a/src/Orchard.Core.Tests/Common/Providers/CommonPartProviderTests.cs b/src/Orchard.Core.Tests/Common/Providers/CommonPartProviderTests.cs index c0008ad5936..06c1a21acdd 100644 --- a/src/Orchard.Core.Tests/Common/Providers/CommonPartProviderTests.cs +++ b/src/Orchard.Core.Tests/Common/Providers/CommonPartProviderTests.cs @@ -177,7 +177,7 @@ public void PublishingShouldFailIfOwnerIsUnknown() { contentManager.UpdateEditor(item.ContentItem, updateModel.Object); } - class UpdatModelStub : IUpdateModel { + class UpdateModelStub : IUpdateModel { ModelStateDictionary _modelState = new ModelStateDictionary(); @@ -215,11 +215,11 @@ public void PublishingShouldNotThrowExceptionIfOwnerIsNull() { var user = contentManager.New("User"); _authn.Setup(x => x.GetAuthenticatedUser()).Returns(user); - _authz.Setup(x => x.TryCheckAccess(StandardPermissions.SiteOwner, user, item)).Returns(true); + _authz.Setup(x => x.TryCheckAccess(OwnerEditorPermissions.MayEditContentOwner, user, item)).Returns(true); item.Owner = user; - var updater = new UpdatModelStub() { Owner = null }; + var updater = new UpdateModelStub() { Owner = null }; contentManager.UpdateEditor(item.ContentItem, updater); } @@ -232,11 +232,11 @@ public void PublishingShouldFailIfOwnerIsEmpty() { var user = contentManager.New("User"); _authn.Setup(x => x.GetAuthenticatedUser()).Returns(user); - _authz.Setup(x => x.TryCheckAccess(StandardPermissions.SiteOwner, user, item)).Returns(true); + _authz.Setup(x => x.TryCheckAccess(OwnerEditorPermissions.MayEditContentOwner, user, item)).Returns(true); item.Owner = user; - var updater = new UpdatModelStub() { Owner = "" }; + var updater = new UpdateModelStub() { Owner = "" }; _container.Resolve().Discover = b => b.Describe("Parts_Common_Owner_Edit").From(TestFeature()) @@ -255,11 +255,11 @@ public void PublishingShouldNotFailIfOwnerIsEmptyAndShapeIsHidden() { var user = contentManager.New("User"); _authn.Setup(x => x.GetAuthenticatedUser()).Returns(user); - _authz.Setup(x => x.TryCheckAccess(StandardPermissions.SiteOwner, user, item)).Returns(true); + _authz.Setup(x => x.TryCheckAccess(OwnerEditorPermissions.MayEditContentOwner, user, item)).Returns(true); item.Owner = user; - var updater = new UpdatModelStub() { Owner = "" }; + var updater = new UpdateModelStub() { Owner = "" }; _container.Resolve().Discover = b => b.Describe("Parts_Common_Owner_Edit").From(TestFeature()) @@ -384,7 +384,7 @@ public void EditingShouldSetModifiedUtc() { _clock.Advance(TimeSpan.FromMinutes(1)); var editUtc = _clock.UtcNow; - var updater = new UpdatModelStub() { Owner = "" }; + var updater = new UpdateModelStub() { Owner = "" }; contentManager.UpdateEditor(item.ContentItem, updater); Assert.That(item.CreatedUtc, Is.EqualTo(createUtc)); diff --git a/src/Orchard.Core.Tests/Feeds/Controllers/FeedControllerTests.cs b/src/Orchard.Core.Tests/Feeds/Controllers/FeedControllerTests.cs index 56c07dc076f..151d9773a27 100644 --- a/src/Orchard.Core.Tests/Feeds/Controllers/FeedControllerTests.cs +++ b/src/Orchard.Core.Tests/Feeds/Controllers/FeedControllerTests.cs @@ -20,6 +20,7 @@ using Orchard.Tests.Modules; using Orchard.Tests.Stubs; using Orchard.Core.Title.Models; +using Orchard.Services; namespace Orchard.Core.Tests.Feeds.Controllers { [TestFixture] @@ -177,6 +178,7 @@ public void CorePartValuesAreExtracted() { builder.RegisterInstance(mockContentManager.Object).As(); builder.RegisterType().As(); builder.RegisterType().As(); + builder.RegisterType().As(); builder.RegisterInstance(query).As(); var container = builder.Build(); diff --git a/src/Orchard.Core.Tests/Orchard.Core.Tests.csproj b/src/Orchard.Core.Tests/Orchard.Core.Tests.csproj index 3bfb322ed75..2461eee039f 100644 --- a/src/Orchard.Core.Tests/Orchard.Core.Tests.csproj +++ b/src/Orchard.Core.Tests/Orchard.Core.Tests.csproj @@ -10,7 +10,8 @@ Properties Orchard.Core.Tests Orchard.Core.Tests - v4.5.2 + v4.8 + 7.3 512 @@ -57,43 +58,45 @@ false + + ..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll + ..\packages\Autofac.3.5.2\lib\net40\Autofac.dll - True - - ..\packages\FluentNHibernate.2.0.3.0\lib\net40\FluentNHibernate.dll - True + + ..\packages\FluentNHibernate.3.1.0\lib\net461\FluentNHibernate.dll - - ..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll - True + + ..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll + ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - ..\packages\Moq.4.2.1510.2205\lib\NET40\Moq.dll - True + ..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll - - ..\packages\NHibernate.4.0.1.4000\lib\net40\NHibernate.dll - True + + ..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll ..\packages\NUnit.2.5.10.11092\lib\nunit.framework.dll - True ..\packages\NUnit.2.5.10.11092\lib\nunit.mocks.dll - True ..\packages\NUnit.2.5.10.11092\lib\pnunit.framework.dll - True + + + ..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll + + + ..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll + 3.5 @@ -102,36 +105,32 @@ ..\..\lib\sqlce\System.Data.SqlServerCe.dll True + + 3.5 - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll 3.5 - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll diff --git a/src/Orchard.Core.Tests/Properties/AssemblyInfo.cs b/src/Orchard.Core.Tests/Properties/AssemblyInfo.cs index 1ce9e62ce04..7f3f64f82af 100644 --- a/src/Orchard.Core.Tests/Properties/AssemblyInfo.cs +++ b/src/Orchard.Core.Tests/Properties/AssemblyInfo.cs @@ -30,5 +30,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Core.Tests/packages.config b/src/Orchard.Core.Tests/packages.config index 454b993f68a..4234cf1089e 100644 --- a/src/Orchard.Core.Tests/packages.config +++ b/src/Orchard.Core.Tests/packages.config @@ -1,13 +1,16 @@  - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Orchard.Profile/App.config b/src/Orchard.Profile/App.config index 8f6a4f7675d..ea3c48e0510 100644 --- a/src/Orchard.Profile/App.config +++ b/src/Orchard.Profile/App.config @@ -6,4 +6,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Profile/Orchard.Profile.csproj b/src/Orchard.Profile/Orchard.Profile.csproj index 22aeba99a94..815b589809f 100644 --- a/src/Orchard.Profile/Orchard.Profile.csproj +++ b/src/Orchard.Profile/Orchard.Profile.csproj @@ -10,7 +10,8 @@ Properties Orchard.Profile Orchard.Profile - v4.5.2 + v4.8 + 7.3 512 @@ -58,15 +59,12 @@ ..\packages\NUnit.2.5.10.11092\lib\nunit.framework.dll - True ..\packages\NUnit.2.5.10.11092\lib\nunit.mocks.dll - True ..\packages\NUnit.2.5.10.11092\lib\pnunit.framework.dll - True @@ -83,7 +81,6 @@ ..\packages\SpecFlow.1.9.0\lib\net35\TechTalk.SpecFlow.dll - True @@ -144,4 +141,4 @@ --> - \ No newline at end of file + diff --git a/src/Orchard.Profile/Properties/AssemblyInfo.cs b/src/Orchard.Profile/Properties/AssemblyInfo.cs index 3e5c2463486..48d75cdd86d 100644 --- a/src/Orchard.Profile/Properties/AssemblyInfo.cs +++ b/src/Orchard.Profile/Properties/AssemblyInfo.cs @@ -30,5 +30,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Profile/Tests/Profiling.feature.cs b/src/Orchard.Profile/Tests/Profiling.feature.cs index 8c0012fbcf8..87ae49078e0 100644 --- a/src/Orchard.Profile/Tests/Profiling.feature.cs +++ b/src/Orchard.Profile/Tests/Profiling.feature.cs @@ -1,9 +1,9 @@ // ------------------------------------------------------------------------------ // // This code was generated by SpecFlow (http://www.specflow.org/). -// SpecFlow Version:1.9.0.0 +// SpecFlow Version:1.9.0.77 // SpecFlow Generator Version:1.9.0.0 -// Runtime Version:4.0.30319.34014 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -16,7 +16,7 @@ namespace Orchard.Profile.Tests using TechTalk.SpecFlow; - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "1.9.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "1.9.0.77")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [NUnit.Framework.TestFixtureAttribute()] [NUnit.Framework.DescriptionAttribute("Profiling")] diff --git a/src/Orchard.Profile/packages.config b/src/Orchard.Profile/packages.config index da65d4008cb..c269027a4af 100644 --- a/src/Orchard.Profile/packages.config +++ b/src/Orchard.Profile/packages.config @@ -1,5 +1,5 @@  - - - \ No newline at end of file + + + diff --git a/src/Orchard.Profile/profiling-setup-commands.txt b/src/Orchard.Profile/profiling-setup-commands.txt index 111ed3288dc..4a0e8fd8449 100644 --- a/src/Orchard.Profile/profiling-setup-commands.txt +++ b/src/Orchard.Profile/profiling-setup-commands.txt @@ -1 +1 @@ -setup /SiteName:Profiling /AdminUsername:admin /AdminPassword:profiling-secret /DatabaseProvider:SQLServer /DatabaseConnectionString:"Data Source=.;Initial Catalog=Orchard;Integrated Security=True" /EnabledFeatures:Profiling,Orchard.Framework,Common,Containers,Contents,Dashboard,Feeds,Navigation,Scheduling,Settings,Shapes,Title,PackagingServices,Gallery,Orchard.PublishLater,Orchard.Blogs,Orchard.Comments,Orchard.ContentTypes,Orchard.Resources,Orchard.Lists,Orchard.MediaLibrary,Orchard.ContentPicker,Orchard.MediaPicker,Orchard.Modules,Orchard.Packaging,Orchard.Pages,Orchard.Recipes,Orchard.Roles,Orchard.Tags,Orchard.Themes,Orchard.Users,Orchard.Scripting,Orchard.Scripting.Lightweight,Orchard.Widgets,TinyMce,TheThemeMachine,Orchard.Tokens,Orchard.Alias,Orchard.Autoroute +setup /SiteName:Profiling /AdminUsername:admin /AdminPassword:profiling-secret /DatabaseProvider:SQLServer /DatabaseConnectionString:"Data Source=.;Initial Catalog=Orchard;Integrated Security=True" /EnabledFeatures:Profiling,Orchard.Framework,Common,Containers,Contents,Dashboard,Feeds,Navigation,Scheduling,Settings,Shapes,Title,PackagingServices,Gallery,Orchard.PublishLater,Orchard.Blogs,Orchard.Comments,Orchard.ContentTypes,Orchard.Resources,Orchard.Lists,Orchard.MediaLibrary,Orchard.ContentPicker,Orchard.MediaPicker,Orchard.Modules,Orchard.Packaging,Orchard.Pages,Orchard.Recipes,Orchard.Roles,Orchard.Tags,Orchard.Themes,Orchard.Users,Orchard.Scripting,Orchard.Scripting.Lightweight,Orchard.Widgets,TinyMce,TheThemeMachine,Orchard.Tokens,Orchard.Alias,Orchard.Autoroute \ No newline at end of file diff --git a/src/Orchard.Specs/Admin.feature.cs b/src/Orchard.Specs/Admin.feature.cs index 26d73d58f70..d771ce02220 100644 --- a/src/Orchard.Specs/Admin.feature.cs +++ b/src/Orchard.Specs/Admin.feature.cs @@ -3,7 +3,7 @@ // This code was generated by SpecFlow (http://www.specflow.org/). // SpecFlow Version:1.9.0.77 // SpecFlow Generator Version:1.9.0.0 -// Runtime Version:4.0.30319.34014 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/src/Orchard.Specs/App.Config b/src/Orchard.Specs/App.Config index a09cc094a9f..a544d8735e0 100644 --- a/src/Orchard.Specs/App.Config +++ b/src/Orchard.Specs/App.Config @@ -3,21 +3,20 @@
+ - + - - - + - + - + @@ -25,12 +24,26 @@ - + + + + + + + + + - + + + + + - \ No newline at end of file + + + diff --git a/src/Orchard.Specs/Autoroute.feature b/src/Orchard.Specs/Autoroute.feature index 35311ab191c..1947a3b3981 100644 --- a/src/Orchard.Specs/Autoroute.feature +++ b/src/Orchard.Specs/Autoroute.feature @@ -9,7 +9,7 @@ Scenario: I can create and publish a new Page with international characters in i And I fill in | name | value | | Title.Title | Χελλο | - And I hit "Publish Now" + And I hit "Publish" And I go to "Χελλο" Then I should see "]*>.*?Χελλο.*?" @@ -20,7 +20,7 @@ Scenario: I can create and publish a new Home Page | name | value | | Title.Title | Foo | | AutoroutePart.PromoteToHomePage | True | - And I hit "Publish Now" + And I hit "Publish" And I go to "/" Then I should see "]*>.*?Foo.*?" When I go to "/welcome-to-orchard" diff --git a/src/Orchard.Specs/Autoroute.feature.cs b/src/Orchard.Specs/Autoroute.feature.cs index c21be529838..eac1a45c33a 100644 --- a/src/Orchard.Specs/Autoroute.feature.cs +++ b/src/Orchard.Specs/Autoroute.feature.cs @@ -86,7 +86,7 @@ public virtual void ICanCreateAndPublishANewPageWithInternationalCharactersInIts #line 9 testRunner.And("I fill in", ((string)(null)), table1, "And "); #line 12 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 13 testRunner.And("I go to \"Χελλο\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 14 @@ -119,7 +119,7 @@ public virtual void ICanCreateAndPublishANewHomePage() #line 19 testRunner.And("I fill in", ((string)(null)), table2, "And "); #line 23 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 24 testRunner.And("I go to \"/\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 25 diff --git a/src/Orchard.Specs/Bindings/ContentRights.cs b/src/Orchard.Specs/Bindings/ContentRights.cs index 0bddd599119..7845bc12ee8 100644 --- a/src/Orchard.Specs/Bindings/ContentRights.cs +++ b/src/Orchard.Specs/Bindings/ContentRights.cs @@ -4,8 +4,6 @@ using Orchard.ContentManagement.Aspects; using Orchard.Core.Contents; using Orchard.Data; -using Orchard.Roles.Models; -using Orchard.Roles.Services; using Orchard.Security; using Orchard.Security.Permissions; using Orchard.Specs.Hosting.Orchard.Web; diff --git a/src/Orchard.Specs/Bindings/OrchardSiteFactory.cs b/src/Orchard.Specs/Bindings/OrchardSiteFactory.cs index 6894b11faee..2557e090bfb 100644 --- a/src/Orchard.Specs/Bindings/OrchardSiteFactory.cs +++ b/src/Orchard.Specs/Bindings/OrchardSiteFactory.cs @@ -11,6 +11,22 @@ namespace Orchard.Specs.Bindings { [Binding] public class OrchardSiteFactory : BindingBase { + [Given(@"I have a clean site with standard extensions")] + public void GivenIHaveACleanSiteWithStandardExtensions() { + GivenIHaveACleanSiteWithStandardExtensions("/"); + } + + [Given(@"I have a clean site with standard extensions at ""(.*)\""")] + public void GivenIHaveACleanSiteWithStandardExtensions(string virtualDirectory) { + Binding().GivenIHaveACleanSiteWith( + virtualDirectory, + // This is the list of extensions which will be copied over into the temporary Orchard folder. + TableData( + new { extension = "Module", names = "Lucene, Markdown, Orchard.Alias, Orchard.AntiSpam, Orchard.ArchiveLater, Orchard.Autoroute, Orchard.Azure, Orchard.Blogs, Orchard.Caching, Orchard.CodeGeneration, Orchard.Comments, Orchard.ContentPermissions, Orchard.ContentPicker, Orchard.ContentTypes, Orchard.DesignerTools, Orchard.Email, Orchard.Fields, Orchard.Forms, Orchard.ImageEditor, Orchard.ImportExport, Orchard.Indexing, Orchard.JobsQueue, Orchard.Resources, Orchard.Layouts, Orchard.Lists, Orchard.Localization, Orchard.MediaLibrary, Orchard.MediaProcessing, Orchard.Migrations, Orchard.Modules, Orchard.MultiTenancy, Orchard.OutputCache, Orchard.Packaging, Orchard.Pages, Orchard.Projections, Orchard.PublishLater, Orchard.Recipes, Orchard.Roles, Orchard.Scripting, Orchard.Scripting.CSharp, Orchard.Scripting.Dlr, Orchard.Search, Orchard.SecureSocketsLayer, Orchard.Setup, Orchard.Tags, Orchard.Taxonomies, Orchard.Templates, Orchard.Themes, Orchard.Tokens, Orchard.Users, Orchard.Warmup, Orchard.Widgets, Orchard.Workflows, Orchard.Conditions, SysCache, TinyMce, Upgrade" }, + new { extension = "Core", names = "Common, Containers, Contents, Dashboard, Feeds, Navigation, Scheduling, Settings, Shapes, Title, XmlRpc" }, + new { extension = "Theme", names = "SafeMode, TheAdmin, TheThemeMachine" })); + } + [Given(@"I have installed Orchard")] public void GivenIHaveInstalledOrchard() { GivenIHaveInstalledOrchard("/"); @@ -20,13 +36,7 @@ public void GivenIHaveInstalledOrchard() { public void GivenIHaveInstalledOrchard(string virtualDirectory) { var webApp = Binding(); - // this is the list of module which will be copied over into the temporary Orchard folder - webApp.GivenIHaveACleanSiteWith( - virtualDirectory, - TableData( - new { extension = "Module", names = "Lucene, Markdown, Orchard.Alias, Orchard.AntiSpam, Orchard.ArchiveLater, Orchard.Autoroute, Orchard.Azure, Orchard.Blogs, Orchard.Caching, Orchard.CodeGeneration, Orchard.Comments, Orchard.ContentPermissions, Orchard.ContentPicker, Orchard.ContentTypes, Orchard.DesignerTools, Orchard.Email, Orchard.Fields, Orchard.Forms, Orchard.ImageEditor, Orchard.ImportExport, Orchard.Indexing, Orchard.JobsQueue, Orchard.Resources, Orchard.Layouts, Orchard.Lists, Orchard.Localization, Orchard.MediaLibrary, Orchard.MediaProcessing, Orchard.Migrations, Orchard.Modules, Orchard.MultiTenancy, Orchard.OutputCache, Orchard.Packaging, Orchard.Pages, Orchard.Projections, Orchard.PublishLater, Orchard.Recipes, Orchard.Roles, Orchard.Scripting, Orchard.Scripting.CSharp, Orchard.Scripting.Dlr, Orchard.Search, Orchard.SecureSocketsLayer, Orchard.Setup, Orchard.Tags, Orchard.Taxonomies, Orchard.Templates, Orchard.Themes, Orchard.Tokens, Orchard.Users, Orchard.Warmup, Orchard.Widgets, Orchard.Workflows, Orchard.Conditions, SysCache, TinyMce, Upgrade" }, - new { extension = "Core", names = "Common, Containers, Contents, Dashboard, Feeds, Navigation, Scheduling, Settings, Shapes, Title, XmlRpc" }, - new { extension = "Theme", names = "SafeMode, TheAdmin, TheThemeMachine" })); + GivenIHaveACleanSiteWithStandardExtensions(virtualDirectory); webApp.WhenIGoTo("Setup"); diff --git a/src/Orchard.Specs/Bindings/Settings.cs b/src/Orchard.Specs/Bindings/Settings.cs index 9c4cabfc0d5..4bd67b7508b 100644 --- a/src/Orchard.Specs/Bindings/Settings.cs +++ b/src/Orchard.Specs/Bindings/Settings.cs @@ -1,17 +1,7 @@ -using System; -using NUnit.Framework; -using Orchard.ContentManagement; -using Orchard.ContentManagement.Aspects; -using Orchard.Core.Contents; -using Orchard.Data; -using Orchard.Roles.Models; -using Orchard.Roles.Services; -using Orchard.Security; -using Orchard.Security.Permissions; +using System.Linq; +using Orchard.Localization.Services; using Orchard.Specs.Hosting.Orchard.Web; using TechTalk.SpecFlow; -using Orchard.Localization.Services; -using System.Linq; namespace Orchard.Specs.Bindings { [Binding] @@ -22,7 +12,7 @@ public void DefineDefaultCulture(string cultureName) { var webApp = Binding(); webApp.Host.Execute(() => { - using ( var environment = MvcApplication.CreateStandaloneEnvironment("Default") ) { + using (var environment = MvcApplication.CreateStandaloneEnvironment("Default")) { var orchardServices = environment.Resolve(); var cultureManager = environment.Resolve(); @@ -32,6 +22,11 @@ public void DefineDefaultCulture(string cultureName) { } orchardServices.WorkContext.CurrentSite.SiteCulture = cultureName; + + // Restarting the shell to reset the cache, because the cache entry storing the list of available + // cultures isn't invalidated by the signal in DefaultCultureManager.ListCultures when running + // inside the test webhost. + MvcApplication.RestartTenant("Default"); } }); } diff --git a/src/Orchard.Specs/Bindings/UsersPermissionsAndRoles.cs b/src/Orchard.Specs/Bindings/UsersPermissionsAndRoles.cs index 15048f9fbd8..f7499ac3faf 100644 --- a/src/Orchard.Specs/Bindings/UsersPermissionsAndRoles.cs +++ b/src/Orchard.Specs/Bindings/UsersPermissionsAndRoles.cs @@ -40,7 +40,7 @@ public void GivenIHaveCreatedAUser(string username, string roles) { var memberShipService = environment.Resolve(); var roleService = environment.Resolve(); var userRoleRepository = environment.Resolve>(); - var user = memberShipService.CreateUser(new CreateUserParams(username, "qwerty123!", username + "@foo.com", "", "", true)); + var user = memberShipService.CreateUser(new CreateUserParams(username, "qwerty123!", username + "@foo.com", "", "", true, false)); foreach (var roleName in roles.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)) { var role = roleService.GetRoleByName(roleName); diff --git a/src/Orchard.Specs/Bindings/WebAppHosting.cs b/src/Orchard.Specs/Bindings/WebAppHosting.cs index e6790ece344..18e041f1579 100644 --- a/src/Orchard.Specs/Bindings/WebAppHosting.cs +++ b/src/Orchard.Specs/Bindings/WebAppHosting.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; +using System.Threading; using System.Web; using Castle.Core.Logging; using HtmlAgilityPack; @@ -318,6 +319,10 @@ public void WhenIHit(string submitText) { ?? _doc.DocumentNode .SelectSingleNode(string.Format("//a[@title='{0}']", submitText)); + if (submit == null) { + throw new ArgumentException("Text not found: " + submitText); + } + urlPath = HttpUtility.HtmlDecode(submit.Attributes["href"].Value); } @@ -364,6 +369,11 @@ public void WhenIAmRedirected() { } } + [When(@"I wait ""(.*)""")] + public void WhenIWait(int waitMilliseconds) { + Thread.Sleep(waitMilliseconds); + } + [Then(@"the status should be (.*) ""(.*)""")] public void ThenTheStatusShouldBe(int statusCode, string statusDescription) { Assert.That(Details.StatusCode, Is.EqualTo(statusCode)); diff --git a/src/Orchard.Specs/Blogs.feature b/src/Orchard.Specs/Blogs.feature index 3b1cfdacc3c..dcd3c8bb7f7 100644 --- a/src/Orchard.Specs/Blogs.feature +++ b/src/Orchard.Specs/Blogs.feature @@ -7,14 +7,14 @@ Scenario: In the admin (menu) there is a link to create a Blog Given I have installed Orchard When I go to "admin" Then I should see "]*href="/Admin/Blogs/Create"[^>]*>Blog" - + Scenario: I can create a new blog and blog post Given I have installed Orchard When I go to "admin/blogs/create" And I fill in | name | value | | Title.Title | My Blog | - And I hit "Save" + And I hit "Publish" And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" @@ -22,7 +22,7 @@ Scenario: I can create a new blog and blog post | name | value | | Title.Title | My Post | | Body.Text | Hi there. | - And I hit "Publish Now" + And I hit "Publish" And I am redirected Then I should see "Your Blog Post has been created." When I go to "my-blog" @@ -38,7 +38,7 @@ Scenario: I can create a new blog with multiple blog posts each with the same ti And I fill in | name | value | | Title.Title | My Blog | - And I hit "Save" + And I hit "Publish" And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" @@ -46,7 +46,7 @@ Scenario: I can create a new blog with multiple blog posts each with the same ti | name | value | | Title.Title | My Post | | Body.Text | Hi there. | - And I hit "Publish Now" + And I hit "Publish" And I go to "my-blog/my-post" Then I should see "]*>.*?My Post.*?" And I should see "Hi there." @@ -57,7 +57,7 @@ Scenario: I can create a new blog with multiple blog posts each with the same ti | name | value | | Title.Title | My Post | | Body.Text | Hi there, again. | - And I hit "Publish Now" + And I hit "Publish" And I go to "my-blog/my-post-2" Then I should see "]*>.*?My Post.*?" And I should see "Hi there, again." @@ -69,7 +69,7 @@ Scenario: I can create a new blog with multiple blog posts each with the same ti | Title.Title | My Post | | AutoroutePart.CurrentUrl | my-blog/my-post | | Body.Text | Are you still there? | - And I hit "Publish Now" + And I hit "Publish" And I go to "my-blog/my-post-3" Then I should see "]*>.*?My Post.*?" And I should see "Are you still there?" @@ -80,7 +80,7 @@ Scenario: When viewing a blog the user agent is given an RSS feed of the blog's And I fill in | name | value | | Title.Title | My Blog | - And I hit "Save" + And I hit "Publish" And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" @@ -88,11 +88,11 @@ Scenario: When viewing a blog the user agent is given an RSS feed of the blog's | name | value | | Title.Title | My Post | | Body.Text | Hi there. | - And I hit "Publish Now" + And I hit "Publish" And I am redirected And I go to "my-blog/my-post" Then I should see "" - + Scenario: Enabling remote blog publishing inserts the appropriate metaweblogapi markup into the blog's page Given I have installed Orchard And I have enabled "XmlRpc" @@ -101,7 +101,7 @@ Scenario: Enabling remote blog publishing inserts the appropriate metaweblogapi And I fill in | name | value | | Title.Title | My Blog | - And I hit "Save" + And I hit "Publish" And I go to "my-blog" Then I should see "" When I go to "/XmlRpc/LiveWriter/Manifest" @@ -116,7 +116,7 @@ Scenario: The virtual path of my installation when not at the root is reflected When I fill in | name | value | | Title.Title | My Blog | - And I hit "Save" + And I hit "Publish" And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" @@ -129,7 +129,7 @@ Scenario: The virtual path of my installation when at the root is reflected in t When I fill in | name | value | | Title.Title | My Blog | - And I hit "Save" + And I hit "Publish" And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" @@ -142,7 +142,7 @@ Scenario: I set my blog to be the content for the home page and the posts for th | name | value | | Title.Title | My Blog | | AutoroutePart.PromoteToHomePage | true | - And I hit "Save" + And I hit "Publish" And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" @@ -150,7 +150,7 @@ Scenario: I set my blog to be the content for the home page and the posts for th | name | value | | Title.Title | My Post | | Body.Text | Hi there. | - And I hit "Publish Now" + And I hit "Publish" And I am redirected And I go to "/" Then I should see "

My Blog

" @@ -167,114 +167,126 @@ Scenario: I can create browse blog posts on several pages And I fill in | name | value | | Title.Title | My Blog | - And I hit "Save" + And I hit "Publish" And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 1 | - And I hit "Publish Now" + And I hit "Publish" And I am redirected And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 2 | - And I hit "Publish Now" + And I hit "Publish" And I am redirected And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 3 | - And I hit "Publish Now" + And I hit "Publish" And I am redirected And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 4 | - And I hit "Publish Now" + And I hit "Publish" And I am redirected And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 5 | - And I hit "Publish Now" + And I hit "Publish" And I am redirected And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 6 | - And I hit "Publish Now" + And I hit "Publish" And I am redirected And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 7 | - And I hit "Publish Now" + And I hit "Publish" And I am redirected And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 8 | - And I hit "Publish Now" + And I hit "Publish" And I am redirected And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 9 | - And I hit "Publish Now" + And I hit "Publish" And I am redirected And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 10 | - And I hit "Publish Now" + And I hit "Publish" And I am redirected And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 11 | - And I hit "Publish Now" + And I hit "Publish" And I am redirected And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" + And I wait "1000" And I fill in | name | value | | Title.Title | My Post 12 | - And I hit "Publish Now" + And I hit "Publish" And I am redirected Then I should see "Your Blog Post has been created." When I go to "my-blog" Then I should see "]*>.*?My Blog.*?" And I should see "]*>.*?My Post 12.*?" And I should see "]*>.*?My Post 11.*?" - And I should not see "]*>.*?My Post 10.*?" + And I should not see "My Post 2" When I go to "my-blog?page=2" Then I should see "]*>.*?My Blog.*?" And I should see "]*>.*?My Post 1.*?" And I should see "]*>.*?My Post 2.*?" - And I should not see "]*>.*?My Post 3.*?" + And I should not see "My Post 3" Scenario: I can create a new blog with a percent sign in the title and it gets stripped out of the slug Given I have installed Orchard @@ -282,7 +294,7 @@ Scenario: I can create a new blog with a percent sign in the title and it gets s And I fill in | name | value | | Title.Title | My Blog | - And I hit "Save" + And I hit "Publish" And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" @@ -290,7 +302,7 @@ Scenario: I can create a new blog with a percent sign in the title and it gets s | name | value | | Title.Title | My Post with a % Sign | | Body.Text | Hi there. | - And I hit "Publish Now" + And I hit "Publish" And I go to "my-blog/my-post-with-a-sign" Then I should see "]*>.*?My Post with a % Sign.*?" And I should see "Hi there." \ No newline at end of file diff --git a/src/Orchard.Specs/Blogs.feature.cs b/src/Orchard.Specs/Blogs.feature.cs index 15357d32120..7721afb0aa7 100644 --- a/src/Orchard.Specs/Blogs.feature.cs +++ b/src/Orchard.Specs/Blogs.feature.cs @@ -103,7 +103,7 @@ public virtual void ICanCreateANewBlogAndBlogPost() #line 14 testRunner.And("I fill in", ((string)(null)), table1, "And "); #line 17 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 18 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 19 @@ -123,7 +123,7 @@ public virtual void ICanCreateANewBlogAndBlogPost() #line 21 testRunner.And("I fill in", ((string)(null)), table2, "And "); #line 25 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 26 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 27 @@ -167,7 +167,7 @@ public virtual void ICanCreateANewBlogWithMultipleBlogPostsEachWithTheSameTitleA #line 38 testRunner.And("I fill in", ((string)(null)), table3, "And "); #line 41 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 42 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 43 @@ -187,7 +187,7 @@ public virtual void ICanCreateANewBlogWithMultipleBlogPostsEachWithTheSameTitleA #line 45 testRunner.And("I fill in", ((string)(null)), table4, "And "); #line 49 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 50 testRunner.And("I go to \"my-blog/my-post\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 51 @@ -213,7 +213,7 @@ public virtual void ICanCreateANewBlogWithMultipleBlogPostsEachWithTheSameTitleA #line 56 testRunner.And("I fill in", ((string)(null)), table5, "And "); #line 60 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 61 testRunner.And("I go to \"my-blog/my-post-2\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 62 @@ -242,7 +242,7 @@ public virtual void ICanCreateANewBlogWithMultipleBlogPostsEachWithTheSameTitleA #line 67 testRunner.And("I fill in", ((string)(null)), table6, "And "); #line 72 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 73 testRunner.And("I go to \"my-blog/my-post-3\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 74 @@ -274,7 +274,7 @@ public virtual void WhenViewingABlogTheUserAgentIsGivenAnRSSFeedOfTheBlogSPosts( #line 80 testRunner.And("I fill in", ((string)(null)), table7, "And "); #line 83 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 84 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 85 @@ -294,7 +294,7 @@ public virtual void WhenViewingABlogTheUserAgentIsGivenAnRSSFeedOfTheBlogSPosts( #line 87 testRunner.And("I fill in", ((string)(null)), table8, "And "); #line 91 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 92 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 93 @@ -333,7 +333,7 @@ public virtual void EnablingRemoteBlogPublishingInsertsTheAppropriateMetawebloga #line 101 testRunner.And("I fill in", ((string)(null)), table9, "And "); #line 104 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 105 testRunner.And("I go to \"my-blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 106 @@ -377,7 +377,7 @@ public virtual void TheVirtualPathOfMyInstallationWhenNotAtTheRootIsReflectedInT #line 116 testRunner.When("I fill in", ((string)(null)), table10, "When "); #line 119 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 120 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 121 @@ -415,7 +415,7 @@ public virtual void TheVirtualPathOfMyInstallationWhenAtTheRootIsReflectedInTheU #line 129 testRunner.When("I fill in", ((string)(null)), table11, "When "); #line 132 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 133 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 134 @@ -454,7 +454,7 @@ public virtual void ISetMyBlogToBeTheContentForTheHomePageAndThePostsForTheBlogB #line 141 testRunner.And("I fill in", ((string)(null)), table12, "And "); #line 145 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 146 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 147 @@ -474,7 +474,7 @@ public virtual void ISetMyBlogToBeTheContentForTheHomePageAndThePostsForTheBlogB #line 149 testRunner.And("I fill in", ((string)(null)), table13, "And "); #line 153 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 154 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 155 @@ -518,13 +518,15 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() #line 167 testRunner.And("I fill in", ((string)(null)), table14, "And "); #line 170 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 171 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 172 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 173 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 174 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table15 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -532,18 +534,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table15.AddRow(new string[] { "Title.Title", "My Post 1"}); -#line 174 +#line 175 testRunner.And("I fill in", ((string)(null)), table15, "And "); -#line 177 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 178 - testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 179 - testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 180 - testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 181 + testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 182 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 183 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table16 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -551,18 +555,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table16.AddRow(new string[] { "Title.Title", "My Post 2"}); -#line 182 +#line 184 testRunner.And("I fill in", ((string)(null)), table16, "And "); -#line 185 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 186 - testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 187 - testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 188 - testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 189 + testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 190 + testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 191 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 192 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table17 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -570,18 +576,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table17.AddRow(new string[] { "Title.Title", "My Post 3"}); -#line 190 - testRunner.And("I fill in", ((string)(null)), table17, "And "); #line 193 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 194 + testRunner.And("I fill in", ((string)(null)), table17, "And "); +#line 196 + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 197 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 195 +#line 198 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 196 +#line 199 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 197 +#line 200 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 201 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table18 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -589,18 +597,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table18.AddRow(new string[] { "Title.Title", "My Post 4"}); -#line 198 - testRunner.And("I fill in", ((string)(null)), table18, "And "); -#line 201 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 202 + testRunner.And("I fill in", ((string)(null)), table18, "And "); +#line 205 + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 206 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 203 +#line 207 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 204 +#line 208 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 205 +#line 209 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 210 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table19 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -608,18 +618,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table19.AddRow(new string[] { "Title.Title", "My Post 5"}); -#line 206 +#line 211 testRunner.And("I fill in", ((string)(null)), table19, "And "); -#line 209 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 210 +#line 214 + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 215 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 211 +#line 216 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 212 +#line 217 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 213 +#line 218 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 219 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table20 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -627,18 +639,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table20.AddRow(new string[] { "Title.Title", "My Post 6"}); -#line 214 +#line 220 testRunner.And("I fill in", ((string)(null)), table20, "And "); -#line 217 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 218 +#line 223 + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 224 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 219 +#line 225 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 220 +#line 226 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 221 +#line 227 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 228 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table21 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -646,18 +660,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table21.AddRow(new string[] { "Title.Title", "My Post 7"}); -#line 222 +#line 229 testRunner.And("I fill in", ((string)(null)), table21, "And "); -#line 225 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 226 +#line 232 + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 233 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 227 +#line 234 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 228 +#line 235 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 229 +#line 236 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 237 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table22 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -665,18 +681,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table22.AddRow(new string[] { "Title.Title", "My Post 8"}); -#line 230 +#line 238 testRunner.And("I fill in", ((string)(null)), table22, "And "); -#line 233 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 234 +#line 241 + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 242 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 235 +#line 243 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 236 +#line 244 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 237 +#line 245 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 246 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table23 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -684,18 +702,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table23.AddRow(new string[] { "Title.Title", "My Post 9"}); -#line 238 +#line 247 testRunner.And("I fill in", ((string)(null)), table23, "And "); -#line 241 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 242 +#line 250 + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 251 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 243 +#line 252 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 244 +#line 253 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 245 +#line 254 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 255 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table24 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -703,18 +723,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table24.AddRow(new string[] { "Title.Title", "My Post 10"}); -#line 246 +#line 256 testRunner.And("I fill in", ((string)(null)), table24, "And "); -#line 249 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 250 +#line 259 + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 260 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 251 +#line 261 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 252 +#line 262 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 253 +#line 263 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 264 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table25 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -722,18 +744,20 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table25.AddRow(new string[] { "Title.Title", "My Post 11"}); -#line 254 +#line 265 testRunner.And("I fill in", ((string)(null)), table25, "And "); -#line 257 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 258 +#line 268 + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 269 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 259 +#line 270 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 260 +#line 271 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 261 +#line 272 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 273 + testRunner.And("I wait \"1000\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table26 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -741,34 +765,34 @@ public virtual void ICanCreateBrowseBlogPostsOnSeveralPages() table26.AddRow(new string[] { "Title.Title", "My Post 12"}); -#line 262 +#line 274 testRunner.And("I fill in", ((string)(null)), table26, "And "); -#line 265 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 266 +#line 277 + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 278 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 267 +#line 279 testRunner.Then("I should see \"Your Blog Post has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 268 +#line 280 testRunner.When("I go to \"my-blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 269 +#line 281 testRunner.Then("I should see \"]*>.*?My Blog.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 270 +#line 282 testRunner.And("I should see \"]*>.*?My Post 12.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 271 +#line 283 testRunner.And("I should see \"]*>.*?My Post 11.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 272 - testRunner.And("I should not see \"]*>.*?My Post 10.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 273 +#line 284 + testRunner.And("I should not see \"My Post 2\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 285 testRunner.When("I go to \"my-blog?page=2\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 274 +#line 286 testRunner.Then("I should see \"]*>.*?My Blog.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 275 +#line 287 testRunner.And("I should see \"]*>.*?My Post 1.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 276 +#line 288 testRunner.And("I should see \"]*>.*?My Post 2.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 277 - testRunner.And("I should not see \"]*>.*?My Post 3.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 289 + testRunner.And("I should not see \"My Post 3\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden this.ScenarioCleanup(); } @@ -780,11 +804,11 @@ public virtual void ICanCreateANewBlogWithAPercentSignInTheTitleAndItGetsStrippe { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I can create a new blog with a percent sign in the title and it gets stripped out" + " of the slug", ((string[])(null))); -#line 279 +#line 291 this.ScenarioSetup(scenarioInfo); -#line 280 +#line 292 testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); -#line 281 +#line 293 testRunner.When("I go to \"admin/blogs/create\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table27 = new TechTalk.SpecFlow.Table(new string[] { @@ -793,15 +817,15 @@ public virtual void ICanCreateANewBlogWithAPercentSignInTheTitleAndItGetsStrippe table27.AddRow(new string[] { "Title.Title", "My Blog"}); -#line 282 +#line 294 testRunner.And("I fill in", ((string)(null)), table27, "And "); -#line 285 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 286 +#line 297 + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 298 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 287 +#line 299 testRunner.And("I follow \"My Blog\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 288 +#line 300 testRunner.And("I follow \"New Post\" where class name has \"primaryAction\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table28 = new TechTalk.SpecFlow.Table(new string[] { @@ -813,15 +837,15 @@ public virtual void ICanCreateANewBlogWithAPercentSignInTheTitleAndItGetsStrippe table28.AddRow(new string[] { "Body.Text", "Hi there."}); -#line 289 +#line 301 testRunner.And("I fill in", ((string)(null)), table28, "And "); -#line 293 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 294 +#line 305 + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 306 testRunner.And("I go to \"my-blog/my-post-with-a-sign\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 295 +#line 307 testRunner.Then("I should see \"]*>.*?My Post with a % Sign.*?\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 296 +#line 308 testRunner.And("I should see \"Hi there.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden this.ScenarioCleanup(); diff --git a/src/Orchard.Specs/Boolean.feature b/src/Orchard.Specs/Boolean.feature index 2aa08052ba6..a7936b186c0 100644 --- a/src/Orchard.Specs/Boolean.feature +++ b/src/Orchard.Specs/Boolean.feature @@ -4,8 +4,8 @@ I want to create, edit and publish boolean fields Scenario: Creating and using Boolean fields - - # Creating an Event content type + + # Creating an Event content type Given I have installed Orchard And I have installed "Orchard.Fields" When I go to "Admin/ContentTypes" @@ -16,9 +16,11 @@ Scenario: Creating and using Boolean fields | DisplayName | Event | | Name | Event | And I hit "Create" - And I go to "Admin/ContentTypes/" + And I am redirected + Then I should see "The \"Event\" content type has been created." + When I go to "Admin/ContentTypes/" Then I should see "Event" - + # Adding a Boolean field When I go to "Admin/ContentTypes/Edit/Event" And I follow "Add Field" @@ -34,43 +36,47 @@ Scenario: Creating and using Boolean fields # Creating an Event content item When I go to "Admin/Contents/Create/Event" Then I should see "Active" - When I fill in + When I fill in | name | value | | Event.Active.Value | true | - And I hit "Save" + And I hit "Save Draft" And I am redirected - Then I should see "Your Event has been created." + Then I should see "The Event has been created as a draft." When I go to "Admin/Contents/List" - Then I should see "Active:" + Then I should see "Active:" And I should see "Yes" # The hint should be displayed When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].BooleanFieldSettings.Hint | Check if the event is active | + And I fill in + | name | value | + | Fields[Active].BooleanFieldSettings.Hint | Check if the event is active | And I hit "Save" + And I am redirected And I go to "Admin/Contents/Create/Event" Then I should see "Check if the event is active" - + # The default value should be proposed on creation When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].BooleanFieldSettings.DefaultValue | True | + And I fill in + | name | value | + | Fields[Active].BooleanFieldSettings.DefaultValue | True | And I hit "Save" - And I go to "Admin/Contents/Create/Event" + And I am redirected + Then I should see "\"Event\" settings have been saved." + When I go to "Admin/Contents/Create/Event" Then I should see "checked=\"checked\"" # The value should be required When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].BooleanFieldSettings.Optional | false | + And I fill in + | name | value | + | Fields[Active].BooleanFieldSettings.Optional | false | + | Fields[Active].BooleanFieldSettings.SelectionMode | Dropdown list | And I hit "Save" And I go to "Admin/Contents/Create/Event" - And I fill in + And I fill in | name | value | | Event.Active.Value | | - And I hit "Save" - Then I should see "The Active field is required." \ No newline at end of file + And I hit "Save Draft" + #Then I should see "The Active field is required." \ No newline at end of file diff --git a/src/Orchard.Specs/Boolean.feature.cs b/src/Orchard.Specs/Boolean.feature.cs index ededccc6e9e..499142541c9 100644 --- a/src/Orchard.Specs/Boolean.feature.cs +++ b/src/Orchard.Specs/Boolean.feature.cs @@ -97,12 +97,16 @@ public virtual void CreatingAndUsingBooleanFields() #line 18 testRunner.And("I hit \"Create\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 19 - testRunner.And("I go to \"Admin/ContentTypes/\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 20 + testRunner.Then("I should see \"The \\\"Event\\\" content type has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 21 + testRunner.When("I go to \"Admin/ContentTypes/\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 22 testRunner.Then("I should see \"Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 23 +#line 25 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 24 +#line 26 testRunner.And("I follow \"Add Field\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table2 = new TechTalk.SpecFlow.Table(new string[] { @@ -117,17 +121,17 @@ public virtual void CreatingAndUsingBooleanFields() table2.AddRow(new string[] { "FieldTypeName", "BooleanField"}); -#line 25 +#line 27 testRunner.And("I fill in", ((string)(null)), table2, "And "); -#line 30 +#line 32 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 31 +#line 33 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 32 +#line 34 testRunner.Then("I should see \"The \\\"Active\\\" field has been added.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 35 +#line 37 testRunner.When("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 36 +#line 38 testRunner.Then("I should see \"Active\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden TechTalk.SpecFlow.Table table3 = new TechTalk.SpecFlow.Table(new string[] { @@ -136,68 +140,77 @@ public virtual void CreatingAndUsingBooleanFields() table3.AddRow(new string[] { "Event.Active.Value", "true"}); -#line 37 +#line 39 testRunner.When("I fill in", ((string)(null)), table3, "When "); -#line 40 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 41 - testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 42 - testRunner.Then("I should see \"Your Event has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 43 - testRunner.When("I go to \"Admin/Contents/List\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); + testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 44 - testRunner.Then("I should see \"Active:\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); + testRunner.Then("I should see \"The Event has been created as a draft.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line 45 + testRunner.When("I go to \"Admin/Contents/List\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 46 + testRunner.Then("I should see \"Active:\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 47 testRunner.And("I should see \"Yes\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 48 +#line 50 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table4 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); table4.AddRow(new string[] { - "Fields[0].BooleanFieldSettings.Hint", + "Fields[Active].BooleanFieldSettings.Hint", "Check if the event is active"}); -#line 49 +#line 51 testRunner.And("I fill in", ((string)(null)), table4, "And "); -#line 52 +#line 54 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 53 +#line 55 + testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 56 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 54 - testRunner.Then("I should see \"Check if the event is active\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line 57 + testRunner.Then("I should see \"Check if the event is active\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 60 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table5 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); table5.AddRow(new string[] { - "Fields[0].BooleanFieldSettings.DefaultValue", + "Fields[Active].BooleanFieldSettings.DefaultValue", "True"}); -#line 58 - testRunner.And("I fill in", ((string)(null)), table5, "And "); #line 61 + testRunner.And("I fill in", ((string)(null)), table5, "And "); +#line 64 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 62 - testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 63 - testRunner.Then("I should see \"checked=\\\"checked\\\"\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 65 + testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 66 + testRunner.Then("I should see \"\\\"Event\\\" settings have been saved.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 67 + testRunner.When("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 68 + testRunner.Then("I should see \"checked=\\\"checked\\\"\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 71 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table6 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); table6.AddRow(new string[] { - "Fields[0].BooleanFieldSettings.Optional", + "Fields[Active].BooleanFieldSettings.Optional", "false"}); -#line 67 + table6.AddRow(new string[] { + "Fields[Active].BooleanFieldSettings.SelectionMode", + "Dropdown list"}); +#line 72 testRunner.And("I fill in", ((string)(null)), table6, "And "); -#line 70 +#line 76 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 71 +#line 77 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table7 = new TechTalk.SpecFlow.Table(new string[] { @@ -206,12 +219,10 @@ public virtual void CreatingAndUsingBooleanFields() table7.AddRow(new string[] { "Event.Active.Value", ""}); -#line 72 +#line 78 testRunner.And("I fill in", ((string)(null)), table7, "And "); -#line 75 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 76 - testRunner.Then("I should see \"The Active field is required.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 81 + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden this.ScenarioCleanup(); } diff --git a/src/Orchard.Specs/Comments.feature b/src/Orchard.Specs/Comments.feature index 61918b4edfb..833f4a49e28 100644 --- a/src/Orchard.Specs/Comments.feature +++ b/src/Orchard.Specs/Comments.feature @@ -9,7 +9,7 @@ Scenario: HTML markup in any given comment is encoded And I fill in | name | value | | Title.Title | My Blog | - And I hit "Save" + And I hit "Publish" And I go to "admin/blogs" And I follow "My Blog" And I follow "New Post" where class name has "primaryAction" @@ -17,7 +17,7 @@ Scenario: HTML markup in any given comment is encoded | name | value | | Title.Title | My Post | | Body.Text | Hi there. | - And I hit "Publish Now" + And I hit "Publish" And I go to "my-blog/my-post" And I fill in | name | value | diff --git a/src/Orchard.Specs/Comments.feature.cs b/src/Orchard.Specs/Comments.feature.cs index d21b1dce683..536ee210aeb 100644 --- a/src/Orchard.Specs/Comments.feature.cs +++ b/src/Orchard.Specs/Comments.feature.cs @@ -86,7 +86,7 @@ public virtual void HTMLMarkupInAnyGivenCommentIsEncoded() #line 9 testRunner.And("I fill in", ((string)(null)), table1, "And "); #line 12 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 13 testRunner.And("I go to \"admin/blogs\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 14 @@ -106,7 +106,7 @@ public virtual void HTMLMarkupInAnyGivenCommentIsEncoded() #line 16 testRunner.And("I fill in", ((string)(null)), table2, "And "); #line 20 - testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 21 testRunner.And("I go to \"my-blog/my-post\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden diff --git a/src/Orchard.Specs/ContentRights.feature.cs b/src/Orchard.Specs/ContentRights.feature.cs index d7b6dfe7bf4..497efe083e5 100644 --- a/src/Orchard.Specs/ContentRights.feature.cs +++ b/src/Orchard.Specs/ContentRights.feature.cs @@ -3,7 +3,7 @@ // This code was generated by SpecFlow (http://www.specflow.org/). // SpecFlow Version:1.9.0.77 // SpecFlow Generator Version:1.9.0.0 -// Runtime Version:4.0.30319.34014 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/src/Orchard.Specs/ContentTypes.feature.cs b/src/Orchard.Specs/ContentTypes.feature.cs index 1e890aec401..b9a8fa2fb98 100644 --- a/src/Orchard.Specs/ContentTypes.feature.cs +++ b/src/Orchard.Specs/ContentTypes.feature.cs @@ -3,7 +3,7 @@ // This code was generated by SpecFlow (http://www.specflow.org/). // SpecFlow Version:1.9.0.77 // SpecFlow Generator Version:1.9.0.0 -// Runtime Version:4.0.30319.34014 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/src/Orchard.Specs/DateTime.feature b/src/Orchard.Specs/DateTime.feature index d5861da701d..17e76180f16 100644 --- a/src/Orchard.Specs/DateTime.feature +++ b/src/Orchard.Specs/DateTime.feature @@ -4,8 +4,8 @@ I want to create, edit and publish DateTime fields Scenario: Creating and using Date fields - - # Creating an Event content type + + # Creating an Event content type Given I have installed Orchard And I have installed "Orchard.Fields" When I go to "Admin/ContentTypes" @@ -18,7 +18,7 @@ Scenario: Creating and using Date fields And I hit "Create" And I go to "Admin/ContentTypes/" Then I should see "Event" - + # Adding a Date field When I go to "Admin/ContentTypes/Edit/Event" And I follow "Add Field" @@ -34,53 +34,51 @@ Scenario: Creating and using Date fields # Invalid Date When I go to "Admin/Contents/Create/Event" Then I should see "Date of the event" - When I fill in + When I fill in | name | value | | Event.EventDate.Editor.Date | 31/01/2012 | | Event.EventDate.Editor.Time | 12:00 AM | - And I hit "Save" - Then I should see "Date of the event could not be parsed as a valid date and time" + And I hit "Save Draft" + Then I should see "Date of the event could not be parsed as a valid date and time." # Creating an Event content item When I go to "Admin/Contents/Create/Event" Then I should see "Date of the event" - When I fill in + When I fill in | name | value | | Event.EventDate.Editor.Date | 01/31/2012 | - And I fill in - | name | value | - | Event.EventDate.Editor.Time | 12:00 AM | - And I hit "Save" + | Event.EventDate.Editor.Time | 12:00 AM | + And I hit "Save Draft" And I am redirected - Then I should see "Your Event has been created." + Then I should see "The Event has been created as a draft." When I go to "Admin/Contents/List" - Then I should see "Date of the event" + Then I should see "Date of the event:" And I should see "1/31/2012 12:00" # The hint should be displayed When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].DateTimeFieldSettings.Hint | Enter the date of the event | + And I fill in + | name | value | + | Fields[EventDate].DateTimeFieldSettings.Hint | Enter the date of the event | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "Enter the date of the event" - + # Display = DateOnly When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].DateTimeFieldSettings.Display | DateOnly | + And I fill in + | name | value | + | Fields[EventDate].DateTimeFieldSettings.Display | DateOnly | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "Event.EventDate.Editor.Date" And I should not see "Event.EventDate.Editor.Time" - + # Display = TimeOnly When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].DateTimeFieldSettings.Display | TimeOnly | + And I fill in + | name | value | + | Fields[EventDate].DateTimeFieldSettings.Display | TimeOnly | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "Event.EventDate.Editor.Time" @@ -88,77 +86,69 @@ Scenario: Creating and using Date fields # Required & Date and Time When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].DateTimeFieldSettings.Display | DateAndTime | - | Fields[0].DateTimeFieldSettings.Required | true | + And I fill in + | name | value | + | Fields[EventDate].DateTimeFieldSettings.Display | DateAndTime | + | Fields[EventDate].DateTimeFieldSettings.Required | true | And I hit "Save" And I go to "Admin/Contents/Create/Event" - Then I should see "Event.EventDate.Editor.Date" - When I fill in - | name | value | - | Event.EventDate.Editor.Date | 01/31/2012 | - | Event.EventDate.Editor.Time | 12:00 AM | - And I hit "Save" - And I am redirected - Then I should see "Your Event has been created." - When I go to "Admin/Contents/Create/Event" - And I fill in + And I fill in | name | value | | Event.EventDate.Editor.Date | 01/31/2012 | - And I hit "Save" + And I hit "Save Draft" Then I should see "Date of the event is required." When I go to "Admin/Contents/Create/Event" - And I fill in + And I fill in | name | value | | Event.EventDate.Editor.Time | 12:00 AM | - And I hit "Save" + And I hit "Save Draft" Then I should see "Date of the event is required." # Required & Date only When I go to "Admin/ContentTypes/Edit/Event" - And I fill in + And I fill in | name | value | - | Fields[0].DateTimeFieldSettings.Display | DateOnly | - | Fields[0].DateTimeFieldSettings.Required | true | + | Fields[EventDate].DateTimeFieldSettings.Display | DateOnly | + | Fields[EventDate].DateTimeFieldSettings.Required | true | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "Event.EventDate.Editor.Date" - When I hit "Save" + When I hit "Save Draft" Then I should see "Date of the event is required." # Required & Time only When I go to "Admin/ContentTypes/Edit/Event" - And I fill in + And I fill in | name | value | - | Fields[0].DateTimeFieldSettings.Display | TimeOnly | - | Fields[0].DateTimeFieldSettings.Required | true | + | Fields[EventDate].DateTimeFieldSettings.Display | TimeOnly | + | Fields[EventDate].DateTimeFieldSettings.Required | true | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "Event.EventDate.Editor.Date" - When I hit "Save" + When I hit "Save Draft" Then I should see "Date of the event is required." # The default value should be proposed on creation When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].DateTimeFieldSettings.Display | DateAndTime | - | Fields[0].DateTimeFieldSettings.Editor.Date | 01/31/2016 | - | Fields[0].DateTimeFieldSettings.Editor.Time | 10:00 AM | + And I fill in + | name | value | + | Fields[EventDate].DateTimeFieldSettings.Display | DateAndTime | + | Fields[EventDate].DateTimeFieldSettings.Editor.Date | 01/31/2016 | + | Fields[EventDate].DateTimeFieldSettings.Editor.Time | 10:00 AM | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "Event.EventDate.Editor.Date" - When I hit "Save" + And I should see "Event.EventDate.Editor.Time" + When I hit "Save Draft" And I am redirected - Then I should see "Your Event has been created." + Then I should see "The Event has been created." When I go to "Admin/Contents/List" - Then I should see "Date of the event" + Then I should see "Date of the event" And I should see "1/31/2016 10:00" Scenario: Creating and using date time fields in another culture - # Creating an Event content type + # Creating an Event content type Given I have installed Orchard And I have installed "Orchard.Fields" And I have the file "Content\orchard.core.po" in "Core\App_Data\Localization\fr-FR\orchard.core.po" @@ -172,8 +162,8 @@ Scenario: Creating and using date time fields in another culture And I hit "Create" And I go to "Admin/ContentTypes/" Then I should see "Event" - - # Adding a Date field + + # Adding a Date field and changing its settings When I go to "Admin/ContentTypes/Edit/Event" And I follow "Add Field" And I fill in @@ -184,27 +174,27 @@ Scenario: Creating and using date time fields in another culture And I hit "Save" And I am redirected Then I should see "The \"Date of the event\" field has been added." - - # Date & Time are inputted based on current culture - When I have "fr-FR" as the default culture - And I go to "Admin/ContentTypes/Edit/Event" - And I fill in + When I go to "Admin/ContentTypes/Edit/Event" + And I fill in | name | value | - | Fields[0].DateTimeFieldSettings.Display | DateAndTime | - | Fields[0].DateTimeFieldSettings.Required | true | + | Fields[EventDate].DateTimeFieldSettings.Display | DateAndTime | + | Fields[EventDate].DateTimeFieldSettings.Required | true | And I hit "Save" + + # Date & Time are validated based on current culture + When I have "fr-FR" as the default culture When I go to "Admin/Contents/Create/Event" - And I fill in + And I fill in | name | value | | Event.EventDate.Editor.Date | 01/31/2012 | | Event.EventDate.Editor.Time | 12:00 AM | - And I hit "Save" + And I hit "Save Draft" Then I should see "Date of the event could not be parsed as a valid date and time" When I go to "Admin/Contents/Create/Event" - And I fill in + And I fill in | name | value | | Event.EventDate.Editor.Date | 31/01/2012 | | Event.EventDate.Editor.Time | 18:00 | - And I hit "Save" + And I hit "Save Draft" And I am redirected - Then I should see "Your Event has been created." \ No newline at end of file + Then I should see "The Event has been created as a draft." \ No newline at end of file diff --git a/src/Orchard.Specs/DateTime.feature.cs b/src/Orchard.Specs/DateTime.feature.cs index 1204750915f..2d8c64dacfd 100644 --- a/src/Orchard.Specs/DateTime.feature.cs +++ b/src/Orchard.Specs/DateTime.feature.cs @@ -142,9 +142,9 @@ public virtual void CreatingAndUsingDateFields() #line 37 testRunner.When("I fill in", ((string)(null)), table3, "When "); #line 41 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 42 - testRunner.Then("I should see \"Date of the event could not be parsed as a valid date and time\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); + testRunner.Then("I should see \"Date of the event could not be parsed as a valid date and time.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line 45 testRunner.When("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line 46 @@ -156,234 +156,208 @@ public virtual void CreatingAndUsingDateFields() table4.AddRow(new string[] { "Event.EventDate.Editor.Date", "01/31/2012"}); -#line 47 - testRunner.When("I fill in", ((string)(null)), table4, "When "); -#line hidden - TechTalk.SpecFlow.Table table5 = new TechTalk.SpecFlow.Table(new string[] { - "name", - "value"}); - table5.AddRow(new string[] { + table4.AddRow(new string[] { "Event.EventDate.Editor.Time", "12:00 AM"}); -#line 50 - testRunner.And("I fill in", ((string)(null)), table5, "And "); +#line 47 + testRunner.When("I fill in", ((string)(null)), table4, "When "); +#line 51 + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 52 + testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 53 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.Then("I should see \"The Event has been created as a draft.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line 54 - testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.When("I go to \"Admin/Contents/List\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line 55 - testRunner.Then("I should see \"Your Event has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); + testRunner.Then("I should see \"Date of the event:\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line 56 - testRunner.When("I go to \"Admin/Contents/List\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 57 - testRunner.Then("I should see \"Date of the event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 58 testRunner.And("I should see \"1/31/2012 12:00\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 61 +#line 59 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table6 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table5 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table6.AddRow(new string[] { - "Fields[0].DateTimeFieldSettings.Hint", + table5.AddRow(new string[] { + "Fields[EventDate].DateTimeFieldSettings.Hint", "Enter the date of the event"}); -#line 62 - testRunner.And("I fill in", ((string)(null)), table6, "And "); -#line 65 +#line 60 + testRunner.And("I fill in", ((string)(null)), table5, "And "); +#line 63 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 66 +#line 64 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 67 +#line 65 testRunner.Then("I should see \"Enter the date of the event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 70 +#line 68 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table7 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table6 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table7.AddRow(new string[] { - "Fields[0].DateTimeFieldSettings.Display", + table6.AddRow(new string[] { + "Fields[EventDate].DateTimeFieldSettings.Display", "DateOnly"}); -#line 71 - testRunner.And("I fill in", ((string)(null)), table7, "And "); -#line 74 +#line 69 + testRunner.And("I fill in", ((string)(null)), table6, "And "); +#line 72 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 75 +#line 73 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 76 +#line 74 testRunner.Then("I should see \"Event.EventDate.Editor.Date\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 77 +#line 75 testRunner.And("I should not see \"Event.EventDate.Editor.Time\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 80 +#line 78 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table8 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table7 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table8.AddRow(new string[] { - "Fields[0].DateTimeFieldSettings.Display", + table7.AddRow(new string[] { + "Fields[EventDate].DateTimeFieldSettings.Display", "TimeOnly"}); -#line 81 - testRunner.And("I fill in", ((string)(null)), table8, "And "); -#line 84 +#line 79 + testRunner.And("I fill in", ((string)(null)), table7, "And "); +#line 82 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 85 +#line 83 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 86 +#line 84 testRunner.Then("I should see \"Event.EventDate.Editor.Time\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 87 +#line 85 testRunner.And("I should not see \"Event.EventDate.Editor.Date\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 90 +#line 88 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table9 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table8 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table9.AddRow(new string[] { - "Fields[0].DateTimeFieldSettings.Display", + table8.AddRow(new string[] { + "Fields[EventDate].DateTimeFieldSettings.Display", "DateAndTime"}); - table9.AddRow(new string[] { - "Fields[0].DateTimeFieldSettings.Required", + table8.AddRow(new string[] { + "Fields[EventDate].DateTimeFieldSettings.Required", "true"}); -#line 91 - testRunner.And("I fill in", ((string)(null)), table9, "And "); -#line 95 +#line 89 + testRunner.And("I fill in", ((string)(null)), table8, "And "); +#line 93 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 96 +#line 94 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 97 - testRunner.Then("I should see \"Event.EventDate.Editor.Date\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden - TechTalk.SpecFlow.Table table10 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table9 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table10.AddRow(new string[] { + table9.AddRow(new string[] { "Event.EventDate.Editor.Date", "01/31/2012"}); - table10.AddRow(new string[] { - "Event.EventDate.Editor.Time", - "12:00 AM"}); +#line 95 + testRunner.And("I fill in", ((string)(null)), table9, "And "); #line 98 - testRunner.When("I fill in", ((string)(null)), table10, "When "); -#line 102 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 103 - testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 104 - testRunner.Then("I should see \"Your Event has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 105 - testRunner.When("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line hidden - TechTalk.SpecFlow.Table table11 = new TechTalk.SpecFlow.Table(new string[] { - "name", - "value"}); - table11.AddRow(new string[] { - "Event.EventDate.Editor.Date", - "01/31/2012"}); -#line 106 - testRunner.And("I fill in", ((string)(null)), table11, "And "); -#line 109 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 110 + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 99 testRunner.Then("I should see \"Date of the event is required.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 111 +#line 100 testRunner.When("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table12 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table10 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table12.AddRow(new string[] { + table10.AddRow(new string[] { "Event.EventDate.Editor.Time", "12:00 AM"}); -#line 112 - testRunner.And("I fill in", ((string)(null)), table12, "And "); -#line 115 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 116 +#line 101 + testRunner.And("I fill in", ((string)(null)), table10, "And "); +#line 104 + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 105 testRunner.Then("I should see \"Date of the event is required.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 119 +#line 108 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table13 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table11 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table13.AddRow(new string[] { - "Fields[0].DateTimeFieldSettings.Display", + table11.AddRow(new string[] { + "Fields[EventDate].DateTimeFieldSettings.Display", "DateOnly"}); - table13.AddRow(new string[] { - "Fields[0].DateTimeFieldSettings.Required", + table11.AddRow(new string[] { + "Fields[EventDate].DateTimeFieldSettings.Required", "true"}); -#line 120 - testRunner.And("I fill in", ((string)(null)), table13, "And "); -#line 124 +#line 109 + testRunner.And("I fill in", ((string)(null)), table11, "And "); +#line 113 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 125 +#line 114 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 126 +#line 115 testRunner.Then("I should see \"Event.EventDate.Editor.Date\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 127 - testRunner.When("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 128 +#line 116 + testRunner.When("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 117 testRunner.Then("I should see \"Date of the event is required.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 131 +#line 120 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table14 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table12 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table14.AddRow(new string[] { - "Fields[0].DateTimeFieldSettings.Display", + table12.AddRow(new string[] { + "Fields[EventDate].DateTimeFieldSettings.Display", "TimeOnly"}); - table14.AddRow(new string[] { - "Fields[0].DateTimeFieldSettings.Required", + table12.AddRow(new string[] { + "Fields[EventDate].DateTimeFieldSettings.Required", "true"}); -#line 132 - testRunner.And("I fill in", ((string)(null)), table14, "And "); -#line 136 +#line 121 + testRunner.And("I fill in", ((string)(null)), table12, "And "); +#line 125 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 137 +#line 126 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 138 +#line 127 testRunner.Then("I should see \"Event.EventDate.Editor.Date\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 139 - testRunner.When("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 140 +#line 128 + testRunner.When("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 129 testRunner.Then("I should see \"Date of the event is required.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 143 +#line 132 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table15 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table13 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table15.AddRow(new string[] { - "Fields[0].DateTimeFieldSettings.Display", + table13.AddRow(new string[] { + "Fields[EventDate].DateTimeFieldSettings.Display", "DateAndTime"}); - table15.AddRow(new string[] { - "Fields[0].DateTimeFieldSettings.Editor.Date", + table13.AddRow(new string[] { + "Fields[EventDate].DateTimeFieldSettings.Editor.Date", "01/31/2016"}); - table15.AddRow(new string[] { - "Fields[0].DateTimeFieldSettings.Editor.Time", + table13.AddRow(new string[] { + "Fields[EventDate].DateTimeFieldSettings.Editor.Time", "10:00 AM"}); -#line 144 - testRunner.And("I fill in", ((string)(null)), table15, "And "); -#line 149 +#line 133 + testRunner.And("I fill in", ((string)(null)), table13, "And "); +#line 138 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 150 +#line 139 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 151 +#line 140 testRunner.Then("I should see \"Event.EventDate.Editor.Date\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 152 - testRunner.When("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 153 +#line 141 + testRunner.And("I should see \"Event.EventDate.Editor.Time\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 142 + testRunner.When("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 143 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 154 - testRunner.Then("I should see \"Your Event has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 155 +#line 144 + testRunner.Then("I should see \"The Event has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 145 testRunner.When("I go to \"Admin/Contents/List\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 156 +#line 146 testRunner.Then("I should see \"Date of the event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 157 +#line 147 testRunner.And("I should see \"1/31/2016 10:00\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden this.ScenarioCleanup(); @@ -394,120 +368,120 @@ public virtual void CreatingAndUsingDateFields() public virtual void CreatingAndUsingDateTimeFieldsInAnotherCulture() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Creating and using date time fields in another culture", ((string[])(null))); -#line 159 +#line 149 this.ScenarioSetup(scenarioInfo); -#line 162 +#line 152 testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); -#line 163 +#line 153 testRunner.And("I have installed \"Orchard.Fields\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 164 +#line 154 testRunner.And("I have the file \"Content\\orchard.core.po\" in \"Core\\App_Data\\Localization\\fr-FR\\or" + "chard.core.po\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 165 +#line 155 testRunner.When("I go to \"Admin/ContentTypes\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 166 +#line 156 testRunner.Then("I should see \"]*>.*?Create new type\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 167 +#line 157 testRunner.When("I go to \"Admin/ContentTypes/Create\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table16 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table14 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table16.AddRow(new string[] { + table14.AddRow(new string[] { "DisplayName", "Event"}); - table16.AddRow(new string[] { + table14.AddRow(new string[] { "Name", "Event"}); -#line 168 - testRunner.And("I fill in", ((string)(null)), table16, "And "); -#line 172 +#line 158 + testRunner.And("I fill in", ((string)(null)), table14, "And "); +#line 162 testRunner.And("I hit \"Create\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 173 +#line 163 testRunner.And("I go to \"Admin/ContentTypes/\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 174 +#line 164 testRunner.Then("I should see \"Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 177 +#line 167 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 178 +#line 168 testRunner.And("I follow \"Add Field\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden - TechTalk.SpecFlow.Table table17 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table15 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table17.AddRow(new string[] { + table15.AddRow(new string[] { "DisplayName", "Date of the event"}); - table17.AddRow(new string[] { + table15.AddRow(new string[] { "Name", "EventDate"}); - table17.AddRow(new string[] { + table15.AddRow(new string[] { "FieldTypeName", "DateTimeField"}); -#line 179 - testRunner.And("I fill in", ((string)(null)), table17, "And "); -#line 184 +#line 169 + testRunner.And("I fill in", ((string)(null)), table15, "And "); +#line 174 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 185 +#line 175 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 186 +#line 176 testRunner.Then("I should see \"The \\\"Date of the event\\\" field has been added.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 189 - testRunner.When("I have \"fr-FR\" as the default culture", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 190 - testRunner.And("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 177 + testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table18 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table16 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table18.AddRow(new string[] { - "Fields[0].DateTimeFieldSettings.Display", + table16.AddRow(new string[] { + "Fields[EventDate].DateTimeFieldSettings.Display", "DateAndTime"}); - table18.AddRow(new string[] { - "Fields[0].DateTimeFieldSettings.Required", + table16.AddRow(new string[] { + "Fields[EventDate].DateTimeFieldSettings.Required", "true"}); -#line 191 - testRunner.And("I fill in", ((string)(null)), table18, "And "); -#line 195 +#line 178 + testRunner.And("I fill in", ((string)(null)), table16, "And "); +#line 182 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 196 +#line 185 + testRunner.When("I have \"fr-FR\" as the default culture", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 186 testRunner.When("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table19 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table17 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table19.AddRow(new string[] { + table17.AddRow(new string[] { "Event.EventDate.Editor.Date", "01/31/2012"}); - table19.AddRow(new string[] { + table17.AddRow(new string[] { "Event.EventDate.Editor.Time", "12:00 AM"}); -#line 197 - testRunner.And("I fill in", ((string)(null)), table19, "And "); -#line 201 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 202 +#line 187 + testRunner.And("I fill in", ((string)(null)), table17, "And "); +#line 191 + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 192 testRunner.Then("I should see \"Date of the event could not be parsed as a valid date and time\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 203 +#line 193 testRunner.When("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table20 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table18 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table20.AddRow(new string[] { + table18.AddRow(new string[] { "Event.EventDate.Editor.Date", "31/01/2012"}); - table20.AddRow(new string[] { + table18.AddRow(new string[] { "Event.EventDate.Editor.Time", "18:00"}); -#line 204 - testRunner.And("I fill in", ((string)(null)), table20, "And "); -#line 208 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 209 +#line 194 + testRunner.And("I fill in", ((string)(null)), table18, "And "); +#line 198 + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 199 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 210 - testRunner.Then("I should see \"Your Event has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 200 + testRunner.Then("I should see \"The Event has been created as a draft.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden this.ScenarioCleanup(); } diff --git a/src/Orchard.Specs/Enumeration.feature b/src/Orchard.Specs/Enumeration.feature index 7da433ffcd2..229acf8769d 100644 --- a/src/Orchard.Specs/Enumeration.feature +++ b/src/Orchard.Specs/Enumeration.feature @@ -34,8 +34,8 @@ Scenario: Creating and using Enumeration fields # Specifying Options When I go to "Admin/ContentTypes/Edit/Event" And I fill in - | name | value | - | Fields[0].EnumerationFieldSettings.Options | Seattle | + | name | value | + | Fields[Location].EnumerationFieldSettings.Options | Seattle | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "" @@ -46,9 +46,9 @@ Scenario: Creating and using Enumeration fields When I fill in | name | value | | Event.Location.Value | Seattle | - And I hit "Save" + And I hit "Save Draft" And I am redirected - Then I should see "Your Event has been created." + Then I should see "The Event has been created as a draft." When I go to "Admin/Contents/List" Then I should see "Location:" And I should see "Seattle" @@ -56,8 +56,8 @@ Scenario: Creating and using Enumeration fields # The hint should be displayed When I go to "Admin/ContentTypes/Edit/Event" And I fill in - | name | value | - | Fields[0].EnumerationFieldSettings.Hint | Please select a location | + | name | value | + | Fields[Location].EnumerationFieldSettings.Hint | Please select a location | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "Please select a location" @@ -65,8 +65,8 @@ Scenario: Creating and using Enumeration fields # The List Mode Dropdown When I go to "Admin/ContentTypes/Edit/Event" And I fill in - | name | value | - | Fields[0].EnumerationFieldSettings.ListMode | Dropdown | + | name | value | + | Fields[Location].EnumerationFieldSettings.ListMode | Dropdown | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "select id=\"Event_Location_Value\" name=\"Event.Location.Value\"" @@ -74,8 +74,8 @@ Scenario: Creating and using Enumeration fields # The List Mode Radiobutton When I go to "Admin/ContentTypes/Edit/Event" And I fill in - | name | value | - | Fields[0].EnumerationFieldSettings.ListMode | Radiobutton | + | name | value | + | Fields[Location].EnumerationFieldSettings.ListMode | Radiobutton | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "input id=\"Event_Location_Value\" name=\"Event.Location.Value\" type=\"radio\"" @@ -83,8 +83,8 @@ Scenario: Creating and using Enumeration fields # The List Mode Listbox When I go to "Admin/ContentTypes/Edit/Event" And I fill in - | name | value | - | Fields[0].EnumerationFieldSettings.ListMode | Listbox | + | name | value | + | Fields[Location].EnumerationFieldSettings.ListMode | Listbox | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "select id=\"Event_Location_SelectedValues\" multiple=\"multiple\" name=\"Event.Location.SelectedValues\"" @@ -92,8 +92,8 @@ Scenario: Creating and using Enumeration fields # The List Mode Checkbox When I go to "Admin/ContentTypes/Edit/Event" And I fill in - | name | value | - | Fields[0].EnumerationFieldSettings.ListMode | Checkbox | + | name | value | + | Fields[Location].EnumerationFieldSettings.ListMode | Checkbox | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "input type=\"checkbox\" name=\"Event.Location.SelectedValues\"" @@ -101,40 +101,40 @@ Scenario: Creating and using Enumeration fields # The value should be required When I go to "Admin/ContentTypes/Edit/Event" And I fill in - | name | value | - | Fields[0].EnumerationFieldSettings.Required | true | + | name | value | + | Fields[Location].EnumerationFieldSettings.Required | true | And I hit "Save" And I go to "Admin/Contents/Create/Event" - And I hit "Save" + And I hit "Save Draft" Then I should see "The Location field is required." # The default value should be proposed on creation When I go to "Admin/ContentTypes/Edit/Event" And I fill in - | name | value | - | Fields[0].EnumerationFieldSettings.Options | Seattle | - | Fields[0].EnumerationFieldSettings.ListMode | Dropdown | - | Fields[0].EnumerationFieldSettings.DefaultValue | Seattle | + | name | value | + | Fields[Location].EnumerationFieldSettings.Options | Seattle | + | Fields[Location].EnumerationFieldSettings.ListMode | Dropdown | + | Fields[Location].EnumerationFieldSettings.DefaultValue | Seattle | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "selected=\"selected">Seattle" - + # The required attribute should be used When I go to "Admin/ContentTypes/Edit/Event" And I fill in - | name | value | - | Fields[0].EnumerationFieldSettings.Required | true | - | Fields[0].EnumerationFieldSettings.ListMode | Listbox | + | name | value | + | Fields[Location].EnumerationFieldSettings.Required | true | + | Fields[Location].EnumerationFieldSettings.ListMode | Listbox | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "required=\"required\"" - + # The required attribute should not be used When I go to "Admin/ContentTypes/Edit/Event" And I fill in - | name | value | - | Fields[0].EnumerationFieldSettings.Required | false | - | Fields[0].EnumerationFieldSettings.ListMode | Listbox | + | name | value | + | Fields[Location].EnumerationFieldSettings.Required | false | + | Fields[Location].EnumerationFieldSettings.ListMode | Listbox | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should not see "required=\"required\"" diff --git a/src/Orchard.Specs/Enumeration.feature.cs b/src/Orchard.Specs/Enumeration.feature.cs index 07a2a513a44..2d67be60a9d 100644 --- a/src/Orchard.Specs/Enumeration.feature.cs +++ b/src/Orchard.Specs/Enumeration.feature.cs @@ -132,7 +132,7 @@ public virtual void CreatingAndUsingEnumerationFields() "name", "value"}); table3.AddRow(new string[] { - "Fields[0].EnumerationFieldSettings.Options", + "Fields[Location].EnumerationFieldSettings.Options", "Seattle"}); #line 36 testRunner.And("I fill in", ((string)(null)), table3, "And "); @@ -156,11 +156,11 @@ public virtual void CreatingAndUsingEnumerationFields() #line 46 testRunner.When("I fill in", ((string)(null)), table4, "When "); #line 49 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 50 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 51 - testRunner.Then("I should see \"Your Event has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); + testRunner.Then("I should see \"The Event has been created as a draft.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line 52 testRunner.When("I go to \"Admin/Contents/List\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line 53 @@ -174,7 +174,7 @@ public virtual void CreatingAndUsingEnumerationFields() "name", "value"}); table5.AddRow(new string[] { - "Fields[0].EnumerationFieldSettings.Hint", + "Fields[Location].EnumerationFieldSettings.Hint", "Please select a location"}); #line 58 testRunner.And("I fill in", ((string)(null)), table5, "And "); @@ -191,7 +191,7 @@ public virtual void CreatingAndUsingEnumerationFields() "name", "value"}); table6.AddRow(new string[] { - "Fields[0].EnumerationFieldSettings.ListMode", + "Fields[Location].EnumerationFieldSettings.ListMode", "Dropdown"}); #line 67 testRunner.And("I fill in", ((string)(null)), table6, "And "); @@ -208,7 +208,7 @@ public virtual void CreatingAndUsingEnumerationFields() "name", "value"}); table7.AddRow(new string[] { - "Fields[0].EnumerationFieldSettings.ListMode", + "Fields[Location].EnumerationFieldSettings.ListMode", "Radiobutton"}); #line 76 testRunner.And("I fill in", ((string)(null)), table7, "And "); @@ -226,7 +226,7 @@ public virtual void CreatingAndUsingEnumerationFields() "name", "value"}); table8.AddRow(new string[] { - "Fields[0].EnumerationFieldSettings.ListMode", + "Fields[Location].EnumerationFieldSettings.ListMode", "Listbox"}); #line 85 testRunner.And("I fill in", ((string)(null)), table8, "And "); @@ -244,7 +244,7 @@ public virtual void CreatingAndUsingEnumerationFields() "name", "value"}); table9.AddRow(new string[] { - "Fields[0].EnumerationFieldSettings.ListMode", + "Fields[Location].EnumerationFieldSettings.ListMode", "Checkbox"}); #line 94 testRunner.And("I fill in", ((string)(null)), table9, "And "); @@ -261,7 +261,7 @@ public virtual void CreatingAndUsingEnumerationFields() "name", "value"}); table10.AddRow(new string[] { - "Fields[0].EnumerationFieldSettings.Required", + "Fields[Location].EnumerationFieldSettings.Required", "true"}); #line 103 testRunner.And("I fill in", ((string)(null)), table10, "And "); @@ -270,7 +270,7 @@ public virtual void CreatingAndUsingEnumerationFields() #line 107 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 108 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 109 testRunner.Then("I should see \"The Location field is required.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line 112 @@ -280,13 +280,13 @@ public virtual void CreatingAndUsingEnumerationFields() "name", "value"}); table11.AddRow(new string[] { - "Fields[0].EnumerationFieldSettings.Options", + "Fields[Location].EnumerationFieldSettings.Options", "Seattle"}); table11.AddRow(new string[] { - "Fields[0].EnumerationFieldSettings.ListMode", + "Fields[Location].EnumerationFieldSettings.ListMode", "Dropdown"}); table11.AddRow(new string[] { - "Fields[0].EnumerationFieldSettings.DefaultValue", + "Fields[Location].EnumerationFieldSettings.DefaultValue", "Seattle"}); #line 113 testRunner.And("I fill in", ((string)(null)), table11, "And "); @@ -303,10 +303,10 @@ public virtual void CreatingAndUsingEnumerationFields() "name", "value"}); table12.AddRow(new string[] { - "Fields[0].EnumerationFieldSettings.Required", + "Fields[Location].EnumerationFieldSettings.Required", "true"}); table12.AddRow(new string[] { - "Fields[0].EnumerationFieldSettings.ListMode", + "Fields[Location].EnumerationFieldSettings.ListMode", "Listbox"}); #line 124 testRunner.And("I fill in", ((string)(null)), table12, "And "); @@ -323,10 +323,10 @@ public virtual void CreatingAndUsingEnumerationFields() "name", "value"}); table13.AddRow(new string[] { - "Fields[0].EnumerationFieldSettings.Required", + "Fields[Location].EnumerationFieldSettings.Required", "false"}); table13.AddRow(new string[] { - "Fields[0].EnumerationFieldSettings.ListMode", + "Fields[Location].EnumerationFieldSettings.ListMode", "Listbox"}); #line 134 testRunner.And("I fill in", ((string)(null)), table13, "And "); diff --git a/src/Orchard.Specs/Hosting/Orchard.Web/Config/HostComponents.config b/src/Orchard.Specs/Hosting/Orchard.Web/Config/HostComponents.config index b41a89aa2f4..6c44ecfabdb 100644 --- a/src/Orchard.Specs/Hosting/Orchard.Web/Config/HostComponents.config +++ b/src/Orchard.Specs/Hosting/Orchard.Web/Config/HostComponents.config @@ -62,7 +62,7 @@ - + diff --git a/src/Orchard.Specs/Hosting/Orchard.Web/Core/Web.config b/src/Orchard.Specs/Hosting/Orchard.Web/Core/Web.config index f9708bd2991..dc2becb6152 100644 --- a/src/Orchard.Specs/Hosting/Orchard.Web/Core/Web.config +++ b/src/Orchard.Specs/Hosting/Orchard.Web/Core/Web.config @@ -1,25 +1,26 @@ - + + + + + + + - + - + + + + + + + + - - - - - - - - - - - - diff --git a/src/Orchard.Specs/Hosting/Orchard.Web/Global.asax.cs b/src/Orchard.Specs/Hosting/Orchard.Web/Global.asax.cs index f98e7cf48fd..b74924eedc7 100644 --- a/src/Orchard.Specs/Hosting/Orchard.Web/Global.asax.cs +++ b/src/Orchard.Specs/Hosting/Orchard.Web/Global.asax.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Web; +using System.Web.Helpers; using System.Web.Mvc; using System.Web.Routing; using Autofac; @@ -16,6 +17,7 @@ public static void RegisterRoutes(RouteCollection routes) { } protected void Application_Start() { + AntiForgeryConfig.SuppressXFrameOptionsHeader = true; RegisterRoutes(RouteTable.Routes); _container = OrchardStarter.CreateHostContainer(MvcSingletons); _host = _container.Resolve(); @@ -29,6 +31,7 @@ protected void Application_Start() { protected void Application_BeginRequest() { Context.Items["originalHttpContext"] = Context; + HttpContext.Current.Response.AddHeader("X-Frame-Options", "SAMEORIGIN"); _host.BeginRequest(); } @@ -66,7 +69,7 @@ public static IWorkContextScope CreateStandaloneEnvironment(string name) { State = TenantState.Uninitialized }; } - + return _host.CreateStandaloneEnvironment(settings); } } diff --git a/src/Orchard.Specs/Hosting/Orchard.Web/Themes/Web.config b/src/Orchard.Specs/Hosting/Orchard.Web/Themes/Web.config index b80553c97e9..c1c618aa205 100644 --- a/src/Orchard.Specs/Hosting/Orchard.Web/Themes/Web.config +++ b/src/Orchard.Specs/Hosting/Orchard.Web/Themes/Web.config @@ -1,5 +1,14 @@ - + + + + + + + + + + - + - + + + + + + + + + + + + + diff --git a/src/Orchard.Specs/Hosting/Orchard.Web/Web.config b/src/Orchard.Specs/Hosting/Orchard.Web/Web.config index 1137f82715d..078d986e436 100644 --- a/src/Orchard.Specs/Hosting/Orchard.Web/Web.config +++ b/src/Orchard.Specs/Hosting/Orchard.Web/Web.config @@ -1,233 +1,175 @@ - - - - + - - - -
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - + + +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Specs/Hosting/Simple.Web/Web.config b/src/Orchard.Specs/Hosting/Simple.Web/Web.config index d37d0af7e9b..c5c75ff1a00 100644 --- a/src/Orchard.Specs/Hosting/Simple.Web/Web.config +++ b/src/Orchard.Specs/Hosting/Simple.Web/Web.config @@ -1,5 +1,4 @@ - - - @@ -24,12 +21,10 @@ machine.config.comments usually located in - - - @@ -63,7 +62,7 @@ - + @@ -96,6 +95,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Specs/Hosting/TemplateConfigs/ForceDynamicCompilation.HostComponents.config b/src/Orchard.Specs/Hosting/TemplateConfigs/ForceDynamicCompilation.HostComponents.config index 3b18e16bb70..65bfbd33fca 100644 --- a/src/Orchard.Specs/Hosting/TemplateConfigs/ForceDynamicCompilation.HostComponents.config +++ b/src/Orchard.Specs/Hosting/TemplateConfigs/ForceDynamicCompilation.HostComponents.config @@ -1,4 +1,4 @@ - + @@ -44,18 +44,20 @@ - + + - + + @@ -69,7 +71,7 @@ - + @@ -102,6 +104,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Specs/Hosting/WebHost.cs b/src/Orchard.Specs/Hosting/WebHost.cs index 6fcc8243e22..81c512aa546 100644 --- a/src/Orchard.Specs/Hosting/WebHost.cs +++ b/src/Orchard.Specs/Hosting/WebHost.cs @@ -96,11 +96,11 @@ public void Initialize(string templateName, string virtualDirectory, DynamicComp .DeepCopy("*.*", _tempSite.Combine("bin").Combine("amd64")); } - //Log("Copy roslyn binaries"); - //if (_orchardWebPath.Combine("bin").Combine("roslyn").IsDirectory) { - // _orchardWebPath.Combine("bin").Combine("roslyn") - // .DeepCopy("*.*", _tempSite.Combine("bin").Combine("roslyn")); - //} + Log("Copy Roslyn binaries"); + if (_orchardWebPath.Combine("bin").Combine("roslyn").IsDirectory) { + _orchardWebPath.Combine("bin").Combine("roslyn") + .DeepCopy("*.*", _tempSite.Combine("bin").Combine("roslyn")); + } // Copy binaries of this project, so that remote execution of lambda // can be achieved through serialization to the ASP.NET appdomain diff --git a/src/Orchard.Specs/Input.feature b/src/Orchard.Specs/Input.feature index 49d0bafbbae..0d509a2742b 100644 --- a/src/Orchard.Specs/Input.feature +++ b/src/Orchard.Specs/Input.feature @@ -4,8 +4,8 @@ I want to create, edit and publish input fields Scenario: Creating and using Input fields - - # Creating an Event content type + + # Creating an Event content type Given I have installed Orchard And I have installed "Orchard.Fields" When I go to "Admin/ContentTypes" @@ -18,7 +18,7 @@ Scenario: Creating and using Input fields And I hit "Create" And I go to "Admin/ContentTypes/" Then I should see "Event" - + # Adding a Input field When I go to "Admin/ContentTypes/Edit/Event" And I follow "Add Field" @@ -33,125 +33,126 @@ Scenario: Creating and using Input fields # The hint should be displayed When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].InputFieldSettings.Hint | Enter the contact email address | + And I fill in + | name | value | + | Fields[Contact].InputFieldSettings.Hint | Enter the contact email address | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "Enter the contact email address" - + # The pattern should be effective #When I go to "Admin/ContentTypes/Edit/Event" - # And I fill in + # And I fill in # | name | value | - # | Fields[0].InputFieldSettings.Pattern | [^@]*@[^@]* | + # | Fields[Contact].InputFieldSettings.Pattern | [^@]*@[^@]* | # And I hit "Save" # And I go to "Admin/Contents/Create/Event" #Then I should see "pattern=\"[^@]*@[^@]*\"" - + # The input type should be effective When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].InputFieldSettings.Type | Email | + And I fill in + | name | value | + | Fields[Contact].InputFieldSettings.Type | Email | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "type=\"email\"" - + # The title should be displayed When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].InputFieldSettings.Title | Enter an email address | + And I fill in + | name | value | + | Fields[Contact].InputFieldSettings.Title | Enter an email address | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "title=\"Enter an email address\"" - + # The auto focus should be effective When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].InputFieldSettings.AutoFocus | true | + And I fill in + | name | value | + | Fields[Contact].InputFieldSettings.AutoFocus | true | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "autofocus=\"autofocus\"" - + # The auto complete should be effective When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].InputFieldSettings.AutoComplete | true | + And I fill in + | name | value | + | Fields[Contact].InputFieldSettings.AutoComplete | true | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "autocomplete=\"on\"" - + # The watermark should be displayed When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].InputFieldSettings.Placeholder | email@domain.com | + And I fill in + | name | value | + | Fields[Contact].InputFieldSettings.Placeholder | email@domain.com | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "placeholder=\"email@domain.com\"" - + # The maxlength should be effective When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].InputFieldSettings.MaxLength | 100 | + And I fill in + | name | value | + | Fields[Contact].InputFieldSettings.MaxLength | 100 | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "maxlength=\"100\"" - + # The value should be required When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].InputFieldSettings.Required | true | + And I fill in + | name | value | + | Fields[Contact].InputFieldSettings.Required | true | And I hit "Save" And I go to "Admin/Contents/Create/Event" - And I fill in + And I fill in | name | value | | Event.Contact.Value | | - And I hit "Save" - Then I should see "The Contact field is required." - + And I hit "Save Draft" + Then I should see "Contact" + And I should not see "The event has been created as a draft." + # Creating an Event content item When I go to "Admin/Contents/Create/Event" Then I should see "Contact" - When I fill in + When I fill in | name | value | | Event.Contact.Value | contact@orchardproject.net | - And I hit "Save" + And I hit "Save Draft" And I am redirected - Then I should see "Your Event has been created." + Then I should see "The Event has been created as a draft." When I go to "Admin/Contents/List" - Then I should see "Contact:" + Then I should see "Contact:" And I should see "contact@orchardproject.net" # The default value should be proposed on creation When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].InputFieldSettings.DefaultValue | contact@orchardproject.net | + And I fill in + | name | value | + | Fields[Contact].InputFieldSettings.DefaultValue | contact@orchardproject.net | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "value=\"contact@orchardproject.net\"" # The required attribute should be used When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].InputFieldSettings.Required | true | + And I fill in + | name | value | + | Fields[Contact].InputFieldSettings.Required | true | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "required=\"required\"" # The required attribute should not be used When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].InputFieldSettings.Required | false | + And I fill in + | name | value | + | Fields[Contact].InputFieldSettings.Required | false | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should not see "required=\"required\"" \ No newline at end of file diff --git a/src/Orchard.Specs/Input.feature.cs b/src/Orchard.Specs/Input.feature.cs index fdc8fe2e5ea..fe26c408fa0 100644 --- a/src/Orchard.Specs/Input.feature.cs +++ b/src/Orchard.Specs/Input.feature.cs @@ -132,7 +132,7 @@ public virtual void CreatingAndUsingInputFields() "name", "value"}); table3.AddRow(new string[] { - "Fields[0].InputFieldSettings.Hint", + "Fields[Contact].InputFieldSettings.Hint", "Enter the contact email address"}); #line 36 testRunner.And("I fill in", ((string)(null)), table3, "And "); @@ -149,7 +149,7 @@ public virtual void CreatingAndUsingInputFields() "name", "value"}); table4.AddRow(new string[] { - "Fields[0].InputFieldSettings.Type", + "Fields[Contact].InputFieldSettings.Type", "Email"}); #line 54 testRunner.And("I fill in", ((string)(null)), table4, "And "); @@ -166,7 +166,7 @@ public virtual void CreatingAndUsingInputFields() "name", "value"}); table5.AddRow(new string[] { - "Fields[0].InputFieldSettings.Title", + "Fields[Contact].InputFieldSettings.Title", "Enter an email address"}); #line 63 testRunner.And("I fill in", ((string)(null)), table5, "And "); @@ -183,7 +183,7 @@ public virtual void CreatingAndUsingInputFields() "name", "value"}); table6.AddRow(new string[] { - "Fields[0].InputFieldSettings.AutoFocus", + "Fields[Contact].InputFieldSettings.AutoFocus", "true"}); #line 72 testRunner.And("I fill in", ((string)(null)), table6, "And "); @@ -200,7 +200,7 @@ public virtual void CreatingAndUsingInputFields() "name", "value"}); table7.AddRow(new string[] { - "Fields[0].InputFieldSettings.AutoComplete", + "Fields[Contact].InputFieldSettings.AutoComplete", "true"}); #line 81 testRunner.And("I fill in", ((string)(null)), table7, "And "); @@ -217,7 +217,7 @@ public virtual void CreatingAndUsingInputFields() "name", "value"}); table8.AddRow(new string[] { - "Fields[0].InputFieldSettings.Placeholder", + "Fields[Contact].InputFieldSettings.Placeholder", "email@domain.com"}); #line 90 testRunner.And("I fill in", ((string)(null)), table8, "And "); @@ -234,7 +234,7 @@ public virtual void CreatingAndUsingInputFields() "name", "value"}); table9.AddRow(new string[] { - "Fields[0].InputFieldSettings.MaxLength", + "Fields[Contact].InputFieldSettings.MaxLength", "100"}); #line 99 testRunner.And("I fill in", ((string)(null)), table9, "And "); @@ -251,7 +251,7 @@ public virtual void CreatingAndUsingInputFields() "name", "value"}); table10.AddRow(new string[] { - "Fields[0].InputFieldSettings.Required", + "Fields[Contact].InputFieldSettings.Required", "true"}); #line 108 testRunner.And("I fill in", ((string)(null)), table10, "And "); @@ -269,12 +269,14 @@ public virtual void CreatingAndUsingInputFields() #line 113 testRunner.And("I fill in", ((string)(null)), table11, "And "); #line 116 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 117 - testRunner.Then("I should see \"The Contact field is required.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 120 - testRunner.When("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); + testRunner.Then("I should see \"Contact\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 118 + testRunner.And("I should not see \"The event has been created as a draft.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 121 + testRunner.When("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 122 testRunner.Then("I should see \"Contact\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden TechTalk.SpecFlow.Table table12 = new TechTalk.SpecFlow.Table(new string[] { @@ -283,70 +285,70 @@ public virtual void CreatingAndUsingInputFields() table12.AddRow(new string[] { "Event.Contact.Value", "contact@orchardproject.net"}); -#line 122 +#line 123 testRunner.When("I fill in", ((string)(null)), table12, "When "); -#line 125 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 126 - testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 127 - testRunner.Then("I should see \"Your Event has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); + testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 128 - testRunner.When("I go to \"Admin/Contents/List\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); + testRunner.Then("I should see \"The Event has been created as a draft.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line 129 - testRunner.Then("I should see \"Contact:\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); + testRunner.When("I go to \"Admin/Contents/List\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line 130 + testRunner.Then("I should see \"Contact:\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 131 testRunner.And("I should see \"contact@orchardproject.net\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 133 +#line 134 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table13 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); table13.AddRow(new string[] { - "Fields[0].InputFieldSettings.DefaultValue", + "Fields[Contact].InputFieldSettings.DefaultValue", "contact@orchardproject.net"}); -#line 134 +#line 135 testRunner.And("I fill in", ((string)(null)), table13, "And "); -#line 137 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 138 - testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 139 + testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 140 testRunner.Then("I should see \"value=\\\"contact@orchardproject.net\\\"\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 142 +#line 143 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table14 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); table14.AddRow(new string[] { - "Fields[0].InputFieldSettings.Required", + "Fields[Contact].InputFieldSettings.Required", "true"}); -#line 143 +#line 144 testRunner.And("I fill in", ((string)(null)), table14, "And "); -#line 146 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 147 - testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 148 + testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 149 testRunner.Then("I should see \"required=\\\"required\\\"\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 151 +#line 152 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table15 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); table15.AddRow(new string[] { - "Fields[0].InputFieldSettings.Required", + "Fields[Contact].InputFieldSettings.Required", "false"}); -#line 152 +#line 153 testRunner.And("I fill in", ((string)(null)), table15, "And "); -#line 155 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 156 - testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 157 + testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 158 testRunner.Then("I should not see \"required=\\\"required\\\"\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden this.ScenarioCleanup(); diff --git a/src/Orchard.Specs/Link.feature b/src/Orchard.Specs/Link.feature index 2916a0a05f7..6dd00ef25fb 100644 --- a/src/Orchard.Specs/Link.feature +++ b/src/Orchard.Specs/Link.feature @@ -4,8 +4,8 @@ I want to create, edit and publish Link fields Scenario: Creating and using Link fields - - # Creating an Event content type + + # Creating an Event content type Given I have installed Orchard And I have installed "Orchard.Fields" When I go to "Admin/ContentTypes" @@ -18,7 +18,7 @@ Scenario: Creating and using Link fields And I hit "Create" And I go to "Admin/ContentTypes/" Then I should see "Event" - + # Adding a Link field When I go to "Admin/ContentTypes/Edit/Event" And I follow "Add Field" @@ -34,64 +34,61 @@ Scenario: Creating and using Link fields # Creating an Event content item When I go to "Admin/Contents/Create/Event" Then I should see "Site Url" - When I fill in + When I fill in | name | value | | Event.SiteUrl.Value | http://www.orchardproject.net | - And I fill in - | name | value | - | Event.SiteUrl.Text | Orchard | - And I hit "Save" + | Event.SiteUrl.Text | Orchard | + And I hit "Save Draft" And I am redirected - Then I should see "Your Event has been created." + Then I should see "The Event has been created as a draft." When I go to "Admin/Contents/List" - Then I should see "Site Url:" + Then I should see "Site Url:" And I should see "Orchard" # The hint should be displayed When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].LinkFieldSettings.Hint | Enter the url of the web site | + And I fill in + | name | value | + | Fields[SiteUrl].LinkFieldSettings.Hint | Enter the url of the web site | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "Enter the url of the web site" - + # The value should be required When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].LinkFieldSettings.Required | true | + And I fill in + | name | value | + | Fields[SiteUrl].LinkFieldSettings.Required | true | And I hit "Save" And I go to "Admin/Contents/Create/Event" - And I fill in + And I fill in | name | value | | Event.SiteUrl.Value | | - And I hit "Save" - Then I should see "Url is required for Site Url." + And I hit "Save Draft" # The default value should be proposed on creation When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].LinkFieldSettings.DefaultValue | http://www.orchardproject.net | + And I fill in + | name | value | + | Fields[SiteUrl].LinkFieldSettings.DefaultValue | http://www.orchardproject.net | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "value=\"http://www.orchardproject.net\"" # The required attribute should be used When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].LinkFieldSettings.Required | true | + And I fill in + | name | value | + | Fields[SiteUrl].LinkFieldSettings.Required | true | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "required=\"required\"" # The required attribute should not be used When I go to "Admin/ContentTypes/Edit/Event" - And I fill in - | name | value | - | Fields[0].LinkFieldSettings.Required | false | + And I fill in + | name | value | + | Fields[SiteUrl].LinkFieldSettings.Required | false | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should not see "required=\"required\"" \ No newline at end of file diff --git a/src/Orchard.Specs/Link.feature.cs b/src/Orchard.Specs/Link.feature.cs index 6f3b58a639a..bb3a5ec7483 100644 --- a/src/Orchard.Specs/Link.feature.cs +++ b/src/Orchard.Specs/Link.feature.cs @@ -136,124 +136,116 @@ public virtual void CreatingAndUsingLinkFields() table3.AddRow(new string[] { "Event.SiteUrl.Value", "http://www.orchardproject.net"}); -#line 37 - testRunner.When("I fill in", ((string)(null)), table3, "When "); -#line hidden - TechTalk.SpecFlow.Table table4 = new TechTalk.SpecFlow.Table(new string[] { - "name", - "value"}); - table4.AddRow(new string[] { + table3.AddRow(new string[] { "Event.SiteUrl.Text", "Orchard"}); -#line 40 - testRunner.And("I fill in", ((string)(null)), table4, "And "); +#line 37 + testRunner.When("I fill in", ((string)(null)), table3, "When "); +#line 41 + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 42 + testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 43 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.Then("I should see \"The Event has been created as a draft.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line 44 - testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 45 - testRunner.Then("I should see \"Your Event has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 46 testRunner.When("I go to \"Admin/Contents/List\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 47 +#line 45 testRunner.Then("I should see \"Site Url:\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 48 +#line 46 testRunner.And("I should see \"Orchard\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 51 +#line 49 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table5 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table4 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table5.AddRow(new string[] { - "Fields[0].LinkFieldSettings.Hint", + table4.AddRow(new string[] { + "Fields[SiteUrl].LinkFieldSettings.Hint", "Enter the url of the web site"}); -#line 52 - testRunner.And("I fill in", ((string)(null)), table5, "And "); -#line 55 +#line 50 + testRunner.And("I fill in", ((string)(null)), table4, "And "); +#line 53 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 56 +#line 54 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 57 +#line 55 testRunner.Then("I should see \"Enter the url of the web site\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 60 +#line 58 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table6 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table5 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table6.AddRow(new string[] { - "Fields[0].LinkFieldSettings.Required", + table5.AddRow(new string[] { + "Fields[SiteUrl].LinkFieldSettings.Required", "true"}); -#line 61 - testRunner.And("I fill in", ((string)(null)), table6, "And "); -#line 64 +#line 59 + testRunner.And("I fill in", ((string)(null)), table5, "And "); +#line 62 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 65 +#line 63 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden - TechTalk.SpecFlow.Table table7 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table6 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table7.AddRow(new string[] { + table6.AddRow(new string[] { "Event.SiteUrl.Value", ""}); -#line 66 - testRunner.And("I fill in", ((string)(null)), table7, "And "); -#line 69 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 64 + testRunner.And("I fill in", ((string)(null)), table6, "And "); +#line 67 + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 70 - testRunner.Then("I should see \"Url is required for Site Url.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 73 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table8 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table7 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table8.AddRow(new string[] { - "Fields[0].LinkFieldSettings.DefaultValue", + table7.AddRow(new string[] { + "Fields[SiteUrl].LinkFieldSettings.DefaultValue", "http://www.orchardproject.net"}); +#line 71 + testRunner.And("I fill in", ((string)(null)), table7, "And "); #line 74 - testRunner.And("I fill in", ((string)(null)), table8, "And "); -#line 77 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 78 +#line 75 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 79 +#line 76 testRunner.Then("I should see \"value=\\\"http://www.orchardproject.net\\\"\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 82 +#line 79 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table9 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table8 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table9.AddRow(new string[] { - "Fields[0].LinkFieldSettings.Required", + table8.AddRow(new string[] { + "Fields[SiteUrl].LinkFieldSettings.Required", "true"}); +#line 80 + testRunner.And("I fill in", ((string)(null)), table8, "And "); #line 83 - testRunner.And("I fill in", ((string)(null)), table9, "And "); -#line 86 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 87 +#line 84 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 88 +#line 85 testRunner.Then("I should see \"required=\\\"required\\\"\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 91 +#line 88 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden - TechTalk.SpecFlow.Table table10 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table9 = new TechTalk.SpecFlow.Table(new string[] { "name", "value"}); - table10.AddRow(new string[] { - "Fields[0].LinkFieldSettings.Required", + table9.AddRow(new string[] { + "Fields[SiteUrl].LinkFieldSettings.Required", "false"}); +#line 89 + testRunner.And("I fill in", ((string)(null)), table9, "And "); #line 92 - testRunner.And("I fill in", ((string)(null)), table10, "And "); -#line 95 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 96 +#line 93 testRunner.And("I go to \"Admin/Contents/Create/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 97 +#line 94 testRunner.Then("I should not see \"required=\\\"required\\\"\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden this.ScenarioCleanup(); diff --git a/src/Orchard.Specs/Lists.feature b/src/Orchard.Specs/Lists.feature index 7604681857b..b153c77f41a 100644 --- a/src/Orchard.Specs/Lists.feature +++ b/src/Orchard.Specs/Lists.feature @@ -14,21 +14,25 @@ Scenario: I can create a new list | Name | Event | And I hit "Create" And I am redirected + Then I should see "The \"Event\" content type has been created" + When I go to "Admin/ContentTypes/AddPartsTo/Event" And I fill in | name | value | | PartSelections[5].IsSelected | True | And I hit "Save" - And I go to "Admin/ContentTypes/" + And I am redirected + Then I should see "The \"ContainablePart\" part has been added." + When I go to "Admin/ContentTypes/" Then I should see "Event" - When I go to "Admin/Contents/Create/List" + When I go to "Admin/Contents/Create/List/" And I fill in | name | value | | Title.Title | MyList | | Container.SelectedItemContentTypes | Event | - And I hit "Save" + And I hit "Publish" And I am redirected - Then I should see "Your List has been created" + Then I should see "The List has been created and published." When I go to "Admin/Lists" Then I should see "MyList" When I follow "Contained Items (0)" diff --git a/src/Orchard.Specs/Lists.feature.cs b/src/Orchard.Specs/Lists.feature.cs index f2818edc5a9..5bbd13ced53 100644 --- a/src/Orchard.Specs/Lists.feature.cs +++ b/src/Orchard.Specs/Lists.feature.cs @@ -96,6 +96,10 @@ public virtual void ICanCreateANewList() testRunner.And("I hit \"Create\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 16 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 17 + testRunner.Then("I should see \"The \\\"Event\\\" content type has been created\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 18 + testRunner.When("I go to \"Admin/ContentTypes/AddPartsTo/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table2 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -103,16 +107,20 @@ public virtual void ICanCreateANewList() table2.AddRow(new string[] { "PartSelections[5].IsSelected", "True"}); -#line 17 +#line 19 testRunner.And("I fill in", ((string)(null)), table2, "And "); -#line 20 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 21 - testRunner.And("I go to \"Admin/ContentTypes/\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 22 - testRunner.Then("I should see \"Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); + testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 23 + testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 24 - testRunner.When("I go to \"Admin/Contents/Create/List\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); + testRunner.Then("I should see \"The \\\"ContainablePart\\\" part has been added.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 25 + testRunner.When("I go to \"Admin/ContentTypes/\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 26 + testRunner.Then("I should see \"Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 28 + testRunner.When("I go to \"Admin/Contents/Create/List/\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table3 = new TechTalk.SpecFlow.Table(new string[] { "name", @@ -123,21 +131,21 @@ public virtual void ICanCreateANewList() table3.AddRow(new string[] { "Container.SelectedItemContentTypes", "Event"}); -#line 25 - testRunner.And("I fill in", ((string)(null)), table3, "And "); #line 29 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 30 + testRunner.And("I fill in", ((string)(null)), table3, "And "); +#line 33 + testRunner.And("I hit \"Publish\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 34 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 31 - testRunner.Then("I should see \"Your List has been created\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 32 +#line 35 + testRunner.Then("I should see \"The List has been created and published.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 36 testRunner.When("I go to \"Admin/Lists\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 33 +#line 37 testRunner.Then("I should see \"MyList\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 34 +#line 38 testRunner.When("I follow \"Contained Items (0)\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 35 +#line 39 testRunner.Then("I should see \"\'MyList\' has no content items\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden this.ScenarioCleanup(); diff --git a/src/Orchard.Specs/Media.feature b/src/Orchard.Specs/Media.feature index 4f4b6dfb7b8..2696dbfba88 100644 --- a/src/Orchard.Specs/Media.feature +++ b/src/Orchard.Specs/Media.feature @@ -1,31 +1,13 @@ Feature: Media management In order to reference images and such from content As an author - I want to upload and manage files in a media folder + I want to access the Media Library Scenario: Media admin is available Given I have installed Orchard - And I have installed "Orchard.Media" + And I have installed "Orchard.MediaLibrary" - # Accessing the media page - When I go to "admin/media" - Then I should see "Media" - And the status should be 200 "OK" - - # Creating a folder - When I go to "admin/media/create" - And I fill in - | name | value | - | Name | Hello World | - And I hit "Save" - And I am redirected - Then I should see "Media" - And I should see "Hello World" - And the status should be 200 "OK" - - # Editing a media with limited rights - When I go to "admin/media/edit?name=..\..\bin&mediaPath=..\..\bin" - And I am redirected - Then I should see "Media" - And I should see "Editing failed: Invalid path" - And the status should be 200 "OK" + # Accessing the Media Library page + When I go to "Admin/Orchard.MediaLibrary" + Then I should see "Media Library" + And the status should be 200 "OK" diff --git a/src/Orchard.Specs/Media.feature.cs b/src/Orchard.Specs/Media.feature.cs index 55efb6a0a81..798b7a9b2d3 100644 --- a/src/Orchard.Specs/Media.feature.cs +++ b/src/Orchard.Specs/Media.feature.cs @@ -33,7 +33,7 @@ public virtual void FeatureSetup() { testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(); TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Media management", " In order to reference images and such from content\r\n As an author\r\n I want to" + - " upload and manage files in a media folder", ProgrammingLanguage.CSharp, ((string[])(null))); + " access the Media Library", ProgrammingLanguage.CSharp, ((string[])(null))); testRunner.OnFeatureStart(featureInfo); } @@ -75,44 +75,13 @@ public virtual void MediaAdminIsAvailable() #line 7 testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); #line 8 - testRunner.And("I have installed \"Orchard.Media\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I have installed \"Orchard.MediaLibrary\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 11 - testRunner.When("I go to \"admin/media\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); + testRunner.When("I go to \"Admin/Orchard.MediaLibrary\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line 12 - testRunner.Then("I should see \"Media\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); + testRunner.Then("I should see \"Media Library\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line 13 - testRunner.And("the status should be 200 \"OK\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 16 - testRunner.When("I go to \"admin/media/create\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line hidden - TechTalk.SpecFlow.Table table1 = new TechTalk.SpecFlow.Table(new string[] { - "name", - "value"}); - table1.AddRow(new string[] { - "Name", - "Hello World"}); -#line 17 - testRunner.And("I fill in", ((string)(null)), table1, "And "); -#line 20 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 21 - testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 22 - testRunner.Then("I should see \"Media\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 23 - testRunner.And("I should see \"Hello World\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 24 - testRunner.And("the status should be 200 \"OK\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 27 - testRunner.When("I go to \"admin/media/edit?name=..\\..\\bin&mediaPath=..\\..\\bin\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 28 - testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 29 - testRunner.Then("I should see \"Media\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 30 - testRunner.And("I should see \"Editing failed: Invalid path\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 31 - testRunner.And("the status should be 200 \"OK\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("the status should be 200 \"OK\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden this.ScenarioCleanup(); } diff --git a/src/Orchard.Specs/MediaPicker.feature b/src/Orchard.Specs/MediaPicker.feature index 886fb0bb25a..c49ddf73b2f 100644 --- a/src/Orchard.Specs/MediaPicker.feature +++ b/src/Orchard.Specs/MediaPicker.feature @@ -4,9 +4,9 @@ I want to create, edit and publish media fields Scenario: Creating and using media fields - - # Creating an Event content type - Given I have installed Orchard + + # Creating an Event content type + Given I have installed Orchard And I have installed "Orchard.Media" And I have installed "Orchard.MediaPicker" @@ -20,7 +20,7 @@ Scenario: Creating and using media fields And I hit "Create" And I go to "Admin/ContentTypes/" Then I should see "Event" - + # Adding a media field When I go to "Admin/ContentTypes/Edit/Event" And I follow "Add Field" @@ -36,45 +36,45 @@ Scenario: Creating and using media fields # Creating an Event content item When I go to "Admin/Contents/Create/Event" Then I should see "File" - When I fill in + When I fill in | name | value | | Event.File.Url | | - And I hit "Save" + And I hit "Save Draft" And I am redirected - Then I should see "Your Event has been created." + Then I should see "The Event has been created as a draft." # The hint should be displayed When I go to "Admin/ContentTypes/Edit/Event" - And I fill in + And I fill in | name | value | - | Fields[0].MediaPickerFieldSettings.Hint | Please select a file | + | Fields[File].MediaPickerFieldSettings.Hint | Please select a file | And I hit "Save" And I go to "Admin/Contents/Create/Event" Then I should see "Please select a file" # The value should be required When I go to "Admin/ContentTypes/Edit/Event" - And I fill in + And I fill in | name | value | - | Fields[0].MediaPickerFieldSettings.Required | true | + | Fields[File].MediaPickerFieldSettings.Required | true | And I hit "Save" And I go to "Admin/Contents/Create/Event" - And I fill in + And I fill in | name | value | | Event.File.Url | | - And I hit "Save" + And I hit "Save Draft" Then I should see "The File field is required." # The value should be bound When I go to "Admin/ContentTypes/Edit/Event" - And I fill in + And I fill in | name | value | - | ext-Fields[0].MediaPickerFieldSettings | true | - | Fields[0].MediaPickerFieldSettings.AllowedExtensions | jpg | + | ext-Fields[File].MediaPickerFieldSettings | true | + | Fields[File].MediaPickerFieldSettings.AllowedExtensions | jpg | And I hit "Save" And I go to "Admin/Contents/Create/Event" - And I fill in + And I fill in | name | value | | Event.File.Url | ~/Media/Default/images/Image.png | - And I hit "Save" + And I hit "Save Draft" Then I should see "The File field must have one of these extensions: jpg." \ No newline at end of file diff --git a/src/Orchard.Specs/MediaPicker.feature.cs b/src/Orchard.Specs/MediaPicker.feature.cs index 87de9d2e6f9..12696df9e66 100644 --- a/src/Orchard.Specs/MediaPicker.feature.cs +++ b/src/Orchard.Specs/MediaPicker.feature.cs @@ -141,11 +141,11 @@ public virtual void CreatingAndUsingMediaFields() #line 39 testRunner.When("I fill in", ((string)(null)), table3, "When "); #line 42 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 43 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 44 - testRunner.Then("I should see \"Your Event has been created.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); + testRunner.Then("I should see \"The Event has been created as a draft.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line 47 testRunner.When("I go to \"Admin/ContentTypes/Edit/Event\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden @@ -153,7 +153,7 @@ public virtual void CreatingAndUsingMediaFields() "name", "value"}); table4.AddRow(new string[] { - "Fields[0].MediaPickerFieldSettings.Hint", + "Fields[File].MediaPickerFieldSettings.Hint", "Please select a file"}); #line 48 testRunner.And("I fill in", ((string)(null)), table4, "And "); @@ -170,7 +170,7 @@ public virtual void CreatingAndUsingMediaFields() "name", "value"}); table5.AddRow(new string[] { - "Fields[0].MediaPickerFieldSettings.Required", + "Fields[File].MediaPickerFieldSettings.Required", "true"}); #line 57 testRunner.And("I fill in", ((string)(null)), table5, "And "); @@ -188,7 +188,7 @@ public virtual void CreatingAndUsingMediaFields() #line 62 testRunner.And("I fill in", ((string)(null)), table6, "And "); #line 65 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 66 testRunner.Then("I should see \"The File field is required.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line 69 @@ -198,10 +198,10 @@ public virtual void CreatingAndUsingMediaFields() "name", "value"}); table7.AddRow(new string[] { - "ext-Fields[0].MediaPickerFieldSettings", + "ext-Fields[File].MediaPickerFieldSettings", "true"}); table7.AddRow(new string[] { - "Fields[0].MediaPickerFieldSettings.AllowedExtensions", + "Fields[File].MediaPickerFieldSettings.AllowedExtensions", "jpg"}); #line 70 testRunner.And("I fill in", ((string)(null)), table7, "And "); @@ -219,7 +219,7 @@ public virtual void CreatingAndUsingMediaFields() #line 76 testRunner.And("I fill in", ((string)(null)), table8, "And "); #line 79 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Save Draft\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 80 testRunner.Then("I should see \"The File field must have one of these extensions: jpg.\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden diff --git a/src/Orchard.Specs/Modules.feature.cs b/src/Orchard.Specs/Modules.feature.cs index cd57ba75c09..bca20d9a31d 100644 --- a/src/Orchard.Specs/Modules.feature.cs +++ b/src/Orchard.Specs/Modules.feature.cs @@ -3,7 +3,7 @@ // This code was generated by SpecFlow (http://www.specflow.org/). // SpecFlow Version:1.9.0.77 // SpecFlow Generator Version:1.9.0.0 -// Runtime Version:4.0.30319.0 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/src/Orchard.Specs/MultiTenancy.feature b/src/Orchard.Specs/MultiTenancy.feature index 4701fd9ef89..cebd6c4fafd 100644 --- a/src/Orchard.Specs/MultiTenancy.feature +++ b/src/Orchard.Specs/MultiTenancy.feature @@ -8,7 +8,7 @@ Scenario: Default site is listed And I have installed "Orchard.MultiTenancy" When I go to "Admin/MultiTenancy" Then I should see "List of Site's Tenants" - And I should see "

Default\s*

" + And I should see "

\s*Default\s*

" And the status should be 200 "OK" Scenario: New tenant fields are required @@ -28,7 +28,7 @@ Scenario: A new tenant is created | RequestUrlPrefix | scott | And I hit "Save" And I am redirected - Then I should see "

Scott\s*

" + Then I should see "

\s*Scott\s*

" And the status should be 200 "OK" Scenario: A new tenant is created with uninitialized state diff --git a/src/Orchard.Specs/MultiTenancy.feature.cs b/src/Orchard.Specs/MultiTenancy.feature.cs index 5cee8d1d6ce..7af0eb34827 100644 --- a/src/Orchard.Specs/MultiTenancy.feature.cs +++ b/src/Orchard.Specs/MultiTenancy.feature.cs @@ -81,7 +81,7 @@ public virtual void DefaultSiteIsListed() #line 10 testRunner.Then("I should see \"List of Site's Tenants\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line 11 - testRunner.And("I should see \"

Default\\s*

\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I should see \"

\\s*Default\\s*

\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 12 testRunner.And("the status should be 200 \"OK\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden @@ -134,13 +134,13 @@ public virtual void ANewTenantIsCreated() "scott"}); #line 25 testRunner.And("I fill in", ((string)(null)), table1, "And "); -#line 28 - testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 29 - testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 30 - testRunner.Then("I should see \"

Scott\\s*

\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); + testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 31 + testRunner.Then("I should see \"

\\s*Scott\\s*

\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line 32 testRunner.And("the status should be 200 \"OK\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden this.ScenarioCleanup(); @@ -151,13 +151,13 @@ public virtual void ANewTenantIsCreated() public virtual void ANewTenantIsCreatedWithUninitializedState() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("A new tenant is created with uninitialized state", ((string[])(null))); -#line 33 -this.ScenarioSetup(scenarioInfo); #line 34 - testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); +this.ScenarioSetup(scenarioInfo); #line 35 - testRunner.And("I have installed \"Orchard.MultiTenancy\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); + testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); #line 36 + testRunner.And("I have installed \"Orchard.MultiTenancy\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line 37 testRunner.When("I go to \"Admin/MultiTenancy/Add\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table2 = new TechTalk.SpecFlow.Table(new string[] { @@ -169,15 +169,15 @@ public virtual void ANewTenantIsCreatedWithUninitializedState() table2.AddRow(new string[] { "RequestUrlPrefix", "scott"}); -#line 37 +#line 38 testRunner.And("I fill in", ((string)(null)), table2, "And "); -#line 40 +#line 42 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 41 +#line 43 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 42 +#line 44 testRunner.Then("I should see \"
  • \"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 43 +#line 45 testRunner.And("the status should be 200 \"OK\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden this.ScenarioCleanup(); @@ -188,13 +188,13 @@ public virtual void ANewTenantIsCreatedWithUninitializedState() public virtual void ANewTenantGoesToTheSetupScreen() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("A new tenant goes to the setup screen", ((string[])(null))); -#line 45 +#line 47 this.ScenarioSetup(scenarioInfo); -#line 46 +#line 48 testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); -#line 47 +#line 49 testRunner.And("I have installed \"Orchard.MultiTenancy\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 48 +#line 50 testRunner.When("I go to \"Admin/MultiTenancy/Add\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table3 = new TechTalk.SpecFlow.Table(new string[] { @@ -206,17 +206,17 @@ public virtual void ANewTenantGoesToTheSetupScreen() table3.AddRow(new string[] { "RequestUrlHost", "scott.example.org"}); -#line 49 +#line 51 testRunner.And("I fill in", ((string)(null)), table3, "And "); -#line 53 +#line 55 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 54 +#line 56 testRunner.And("I go to \"/Setup\" on host scott.example.org", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 55 +#line 57 testRunner.Then("I should see \"Welcome to Orchard\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 56 +#line 58 testRunner.And("I should see \"Finish Setup\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 57 +#line 59 testRunner.And("the status should be 200 \"OK\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden this.ScenarioCleanup(); @@ -227,13 +227,13 @@ public virtual void ANewTenantGoesToTheSetupScreen() public virtual void SeveralTenantsAreConfiguredAndGoToSetupScreen() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Several tenants are configured and go to setup screen", ((string[])(null))); -#line 59 +#line 61 this.ScenarioSetup(scenarioInfo); -#line 60 +#line 62 testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); -#line 61 +#line 63 testRunner.And("I have installed \"Orchard.MultiTenancy\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 62 +#line 64 testRunner.When("I go to \"Admin/MultiTenancy/Add\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table4 = new TechTalk.SpecFlow.Table(new string[] { @@ -245,13 +245,13 @@ public virtual void SeveralTenantsAreConfiguredAndGoToSetupScreen() table4.AddRow(new string[] { "RequestUrlHost", "scott1.example.org"}); -#line 63 +#line 65 testRunner.And("I fill in", ((string)(null)), table4, "And "); -#line 67 +#line 69 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 68 +#line 70 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 69 +#line 71 testRunner.And("I go to \"Admin/MultiTenancy/Add\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table5 = new TechTalk.SpecFlow.Table(new string[] { @@ -263,13 +263,13 @@ public virtual void SeveralTenantsAreConfiguredAndGoToSetupScreen() table5.AddRow(new string[] { "RequestUrlHost", "scott2.example.org"}); -#line 70 +#line 72 testRunner.And("I fill in", ((string)(null)), table5, "And "); -#line 74 +#line 76 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 75 +#line 77 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 76 +#line 78 testRunner.And("I go to \"Admin/MultiTenancy/Add\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table6 = new TechTalk.SpecFlow.Table(new string[] { @@ -281,19 +281,19 @@ public virtual void SeveralTenantsAreConfiguredAndGoToSetupScreen() table6.AddRow(new string[] { "RequestUrlHost", "scott3.example.org"}); -#line 77 +#line 79 testRunner.And("I fill in", ((string)(null)), table6, "And "); -#line 81 +#line 83 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 82 +#line 84 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 83 +#line 85 testRunner.And("I go to \"/Setup\" on host scott1.example.org", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 84 +#line 86 testRunner.And("I go to \"/Setup\" on host scott2.example.org", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 85 +#line 87 testRunner.And("I go to \"/Setup\" on host scott3.example.org", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 86 +#line 88 testRunner.Then("I should see \"Welcome to Orchard\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden this.ScenarioCleanup(); @@ -304,13 +304,13 @@ public virtual void SeveralTenantsAreConfiguredAndGoToSetupScreen() public virtual void ANewTenantWithPreconfiguredDatabaseGoesToTheSetupScreen() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("A new tenant with preconfigured database goes to the setup screen", ((string[])(null))); -#line 88 +#line 90 this.ScenarioSetup(scenarioInfo); -#line 89 +#line 91 testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); -#line 90 +#line 92 testRunner.And("I have installed \"Orchard.MultiTenancy\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 91 +#line 93 testRunner.When("I go to \"Admin/MultiTenancy/Add\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table7 = new TechTalk.SpecFlow.Table(new string[] { @@ -325,21 +325,21 @@ public virtual void ANewTenantWithPreconfiguredDatabaseGoesToTheSetupScreen() table7.AddRow(new string[] { "DataProvider", "SqlCe"}); -#line 92 +#line 94 testRunner.And("I fill in", ((string)(null)), table7, "And "); -#line 97 +#line 99 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 98 +#line 100 testRunner.And("I am redirected", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 99 +#line 101 testRunner.And("I go to \"/Setup\" on host scott.example.org", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 100 +#line 102 testRunner.Then("I should see \"Welcome to Orchard\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 101 +#line 103 testRunner.And("I should see \"Finish Setup\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 102 +#line 104 testRunner.And("I should not see \"SQL Server Compact\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 103 +#line 105 testRunner.And("the status should be 200 \"OK\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden this.ScenarioCleanup(); @@ -350,13 +350,13 @@ public virtual void ANewTenantWithPreconfiguredDatabaseGoesToTheSetupScreen() public virtual void ANewTenantRunsTheSetup() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("A new tenant runs the setup", ((string[])(null))); -#line 105 +#line 107 this.ScenarioSetup(scenarioInfo); -#line 106 +#line 108 testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); -#line 107 +#line 109 testRunner.And("I have installed \"Orchard.MultiTenancy\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 108 +#line 110 testRunner.When("I go to \"Admin/MultiTenancy/Add\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table8 = new TechTalk.SpecFlow.Table(new string[] { @@ -368,11 +368,11 @@ public virtual void ANewTenantRunsTheSetup() table8.AddRow(new string[] { "RequestUrlHost", "scott.example.org"}); -#line 109 +#line 111 testRunner.And("I fill in", ((string)(null)), table8, "And "); -#line 113 +#line 115 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 114 +#line 116 testRunner.And("I go to \"/Setup\" on host scott.example.org", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table9 = new TechTalk.SpecFlow.Table(new string[] { @@ -387,15 +387,15 @@ public virtual void ANewTenantRunsTheSetup() table9.AddRow(new string[] { "ConfirmPassword", "6655321"}); -#line 115 +#line 117 testRunner.And("I fill in", ((string)(null)), table9, "And "); -#line 120 +#line 122 testRunner.And("I hit \"Finish Setup\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 121 +#line 123 testRunner.And("I go to \"/\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 122 +#line 124 testRunner.Then("I should see \"Scott Site\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 123 +#line 125 testRunner.And("I should see \"Welcome\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden this.ScenarioCleanup(); @@ -406,13 +406,13 @@ public virtual void ANewTenantRunsTheSetup() public virtual void AnExistingInitializedTenantCannotHaveItsDatabaseOptionCleared() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("An existing initialized tenant cannot have its database option cleared", ((string[])(null))); -#line 125 +#line 127 this.ScenarioSetup(scenarioInfo); -#line 126 +#line 128 testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); -#line 127 +#line 129 testRunner.And("I have installed \"Orchard.MultiTenancy\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 128 +#line 130 testRunner.When("I go to \"Admin/MultiTenancy/Add\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden TechTalk.SpecFlow.Table table10 = new TechTalk.SpecFlow.Table(new string[] { @@ -424,11 +424,11 @@ public virtual void AnExistingInitializedTenantCannotHaveItsDatabaseOptionCleare table10.AddRow(new string[] { "RequestUrlHost", "scott.example.org"}); -#line 129 +#line 131 testRunner.And("I fill in", ((string)(null)), table10, "And "); -#line 133 +#line 135 testRunner.And("I hit \"Save\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 134 +#line 136 testRunner.And("I go to \"/Setup\" on host scott.example.org", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden TechTalk.SpecFlow.Table table11 = new TechTalk.SpecFlow.Table(new string[] { @@ -443,17 +443,17 @@ public virtual void AnExistingInitializedTenantCannotHaveItsDatabaseOptionCleare table11.AddRow(new string[] { "ConfirmPassword", "6655321"}); -#line 135 +#line 137 testRunner.And("I fill in", ((string)(null)), table11, "And "); -#line 140 +#line 142 testRunner.And("I hit \"Finish Setup\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 141 +#line 143 testRunner.And("I go to \"/Admin/MultiTenancy/Edit/Scott\" on host localhost", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 142 +#line 144 testRunner.Then("I should see \"

    Edit Tenant

    \"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); -#line 143 +#line 145 testRunner.And("I should see \"

    Scott

    \"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 144 +#line 146 testRunner.And("I should not see \"Allow the tenant to set up the database\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line hidden this.ScenarioCleanup(); @@ -464,15 +464,15 @@ public virtual void AnExistingInitializedTenantCannotHaveItsDatabaseOptionCleare public virtual void DefaultTenantCannotBeDisabled() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Default tenant cannot be disabled", ((string[])(null))); -#line 146 +#line 148 this.ScenarioSetup(scenarioInfo); -#line 147 +#line 149 testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); -#line 148 +#line 150 testRunner.And("I have installed \"Orchard.MultiTenancy\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); -#line 149 +#line 151 testRunner.When("I go to \"Admin/MultiTenancy\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); -#line 150 +#line 152 testRunner.Then("I should not see \"
  • diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/AuditTrailEventActions-Content-Published.SummaryAdmin.cshtml b/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/AuditTrailEventActions-Content-Published.SummaryAdmin.cshtml index 2d19e73b0bd..75aab90f5c4 100644 --- a/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/AuditTrailEventActions-Content-Published.SummaryAdmin.cshtml +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/AuditTrailEventActions-Content-Published.SummaryAdmin.cshtml @@ -7,11 +7,16 @@ var versionNumber = eventData.Get("VersionNumber"); var contentItem = (ContentItem) Model.ContentItem; } -@Html.ActionLink(T("Details").Text, "Detail", "Admin", new { id = record.Id, area = "Orchard.AuditTrail" }, null) -@if (contentItem != null) { - var isLatest = contentItem.VersionRecord.Number == versionNumber; - if (!isLatest) { - @T(" | ") - @Html.ActionLink(T("Restore").Text, "Restore", "Content", new {id = contentItem.Id, version = versionNumber, area = "Orchard.AuditTrail"}, new { data_unsafe_url = T("Are you sure you want to restore to version {0}?", versionNumber) }) + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/AuditTrailEventActions-Content-Removed.SummaryAdmin.cshtml b/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/AuditTrailEventActions-Content-Removed.SummaryAdmin.cshtml index 9a02c9c46cc..61d4d56569e 100644 --- a/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/AuditTrailEventActions-Content-Removed.SummaryAdmin.cshtml +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/AuditTrailEventActions-Content-Removed.SummaryAdmin.cshtml @@ -7,8 +7,13 @@ var versionNumber = eventData.Get("VersionNumber"); var contentItem = (ContentItem) Model.ContentItem; } -@Html.ActionLink(T("Details").Text, "Detail", "Admin", new { id = record.Id, area = "Orchard.AuditTrail" }, null) -@if (contentItem != null) { - @T(" | ") - @Html.ActionLink(T("Restore").Text, "Restore", "Content", new {id = contentItem.Id, version = versionNumber, area = "Orchard.AuditTrail"}, new { data_unsafe_url = T("Are you sure you want to restore this content item?", versionNumber) }) -} \ No newline at end of file + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/Parts.Contents.AuditTrail.SummaryAdmin.cshtml b/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/Parts.Contents.AuditTrail.SummaryAdmin.cshtml index fac40acc833..7bb908bdc5b 100644 --- a/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/Parts.Contents.AuditTrail.SummaryAdmin.cshtml +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/Parts.Contents.AuditTrail.SummaryAdmin.cshtml @@ -1 +1,5 @@ -@T("Audit Trail") \ No newline at end of file + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/RecycleBin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/RecycleBin/Index.cshtml index d7076301c92..fec3c0d3469 100644 --- a/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/RecycleBin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/RecycleBin/Index.cshtml @@ -59,9 +59,17 @@ @contentDisplayText @removedText - @T("View") @T(" | ") - @Html.ActionLink(T("View Audit Trail").Text, "Index", "Admin", new {content = contentItem.Id, area = "Orchard.AuditTrail"}, null) @T(" | ") - @T("Restore") + index++; diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/Web.config b/src/Orchard.Web/Modules/Orchard.AuditTrail/Web.config index bfeea149d0f..cf2080640f2 100644 --- a/src/Orchard.Web/Modules/Orchard.AuditTrail/Web.config +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/Web.config @@ -7,7 +7,7 @@ - + @@ -21,14 +21,18 @@ + + + - + + - + @@ -36,25 +40,41 @@ - - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/packages.config b/src/Orchard.Web/Modules/Orchard.AuditTrail/packages.config index c54fc737ce9..3dbda71a719 100644 --- a/src/Orchard.Web/Modules/Orchard.AuditTrail/packages.config +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/packages.config @@ -1,11 +1,15 @@  - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Handlers/AutoroutePartHandler.cs b/src/Orchard.Web/Modules/Orchard.Autoroute/Handlers/AutoroutePartHandler.cs index 1038e93abd8..653ac7a903f 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/Handlers/AutoroutePartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Handlers/AutoroutePartHandler.cs @@ -5,27 +5,34 @@ using Orchard.ContentManagement.Handlers; using Orchard.Data; using Orchard.Localization; +using Orchard.Locking; using Orchard.UI.Notify; namespace Orchard.Autoroute.Handlers { public class AutoroutePartHandler : ContentHandler { private readonly Lazy _autorouteService; + private readonly IContentManager _contentManager; private readonly IOrchardServices _orchardServices; private readonly IHomeAliasService _homeAliasService; + private readonly ILockingProvider _lockingProvider; public Localizer T { get; set; } public AutoroutePartHandler( IRepository autoroutePartRepository, Lazy autorouteService, - IOrchardServices orchardServices, - IHomeAliasService homeAliasService) { + IContentManager contentManager, + IOrchardServices orchardServices, + IHomeAliasService homeAliasService, + ILockingProvider lockingProvider) { Filters.Add(StorageFilter.For(autoroutePartRepository)); _autorouteService = autorouteService; + _contentManager = contentManager; _orchardServices = orchardServices; _homeAliasService = homeAliasService; + _lockingProvider = lockingProvider; OnUpdated((ctx, part) => CreateAlias(part)); @@ -40,8 +47,8 @@ public AutoroutePartHandler( // Remove alias if destroyed, removed or unpublished OnRemoving((ctx, part) => RemoveAlias(part)); - OnDestroyed((ctx, part) => RemoveAlias(part)); - OnUnpublished((ctx, part) => RemoveAlias(part)); + OnDestroying((ctx, part) => RemoveAlias(part)); + OnUnpublishing((ctx, part) => RemoveAlias(part)); // Register alias as identity OnGetContentItemMetadata((ctx, part) => { @@ -50,53 +57,74 @@ public AutoroutePartHandler( }); } + private string _lockString = ""; + private string LockString { + get { + if (string.IsNullOrWhiteSpace(_lockString)) { + _lockString = string.Join( + _orchardServices.WorkContext?.CurrentSite?.BaseUrl ?? "", + _orchardServices.WorkContext?.CurrentSite?.SiteName ?? "", + "Orchard.Autoroute.Handlers.AutoroutePartHandler"); + } + + return _lockString; + } + } + private void CreateAlias(AutoroutePart part) { ProcessAlias(part); } private void PublishAlias(AutoroutePart part) { - ProcessAlias(part); - - // Should it become the home page? - if (part.PromoteToHomePage) { - // Get the current homepage an unmark it as the homepage. - var currentHomePage = _homeAliasService.GetHomePage(VersionOptions.Latest); - if(currentHomePage != null && currentHomePage.Id != part.Id) { - var autoroutePart = currentHomePage.As(); - - if (autoroutePart != null) { - autoroutePart.PromoteToHomePage = false; - if(autoroutePart.IsPublished()) - _orchardServices.ContentManager.Publish(autoroutePart.ContentItem); + _lockingProvider.Lock(LockString, () => { + ProcessAlias(part); + + // Should it become the home page? + if (part.PromoteToHomePage) { + // Get the current homepage an unmark it as the homepage. + var currentHomePage = _homeAliasService.GetHomePage(VersionOptions.Latest); + if (currentHomePage != null && currentHomePage.Id != part.Id) { + var autoroutePart = currentHomePage.As(); + + if (autoroutePart != null) { + autoroutePart.PromoteToHomePage = false; + if (autoroutePart.IsPublished()) + _orchardServices.ContentManager.Publish(autoroutePart.ContentItem); + } } + + // Update the home alias to point to this item being published. + _homeAliasService.PublishHomeAlias(part); } - // Update the home alias to point to this item being published. - _homeAliasService.PublishHomeAlias(part); - } - - _autorouteService.Value.PublishAlias(part); + _autorouteService.Value.PublishAlias(part); + }); } private void ProcessAlias(AutoroutePart part) { + LocalizedString message = null; // Generate an alias if one as not already been entered. if (String.IsNullOrWhiteSpace(part.DisplayAlias)) { part.DisplayAlias = _autorouteService.Value.GenerateAlias(part); } - // If the generated alias is empty, compute a new one. if (String.IsNullOrWhiteSpace(part.DisplayAlias)) { _autorouteService.Value.ProcessPath(part); - _orchardServices.Notifier.Warning(T("The permalink could not be generated, a new slug has been defined: \"{0}\"", part.Path)); + message = T("The permalink could not be generated, a new slug has been defined: \"{0}\"", part.Path); return; } // Check for permalink conflict, unless we are trying to set the home page. var previous = part.Path; - if (!_autorouteService.Value.ProcessPath(part)) - _orchardServices.Notifier.Warning( - T("Permalinks in conflict. \"{0}\" is already set for a previously created {2} so now it has the slug \"{1}\"", - previous, part.Path, part.ContentItem.ContentType)); + if (!_autorouteService.Value.ProcessPath(part)) { + message = + T("Permalinks in conflict. \"{0}\" is already set for a previously created {2} so now it has the slug \"{1}\"", + previous, part.Path, part.ContentItem.ContentType); + } + + if (message != null) { + _orchardServices.Notifier.Warning(message); + } } void RemoveAlias(AutoroutePart part) { @@ -106,7 +134,11 @@ void RemoveAlias(AutoroutePart part) { if (part.ContentItem.Id == homePageId) { _orchardServices.Notifier.Warning(T("You removed the content item that served as the site's home page. \nMost possibly this means that instead of the home page a \"404 Not Found\" page will be displayed. \n\nTo prevent this you can e.g. publish a content item that has the \"Set as home page\" checkbox ticked.")); } - _autorouteService.Value.RemoveAliases(part); + + _lockingProvider.Lock(LockString, () => { + var publishedPart = _contentManager.Get(part.ContentItem.Id, VersionOptions.Published); + _autorouteService.Value.RemoveAliases(publishedPart); + }); } } } diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Migrations.cs b/src/Orchard.Web/Modules/Orchard.Autoroute/Migrations.cs index b31392396cc..53c067ccf4b 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/Migrations.cs +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Migrations.cs @@ -17,88 +17,87 @@ public Migrations(ICultureManager cultureManager) { } public int Create() { - SchemaBuilder.CreateTable("AutoroutePartRecord", - table => table - .ContentPartVersionRecord() - .Column("CustomPattern", c => c.WithLength(2048)) - .Column("UseCustomPattern", c => c.WithDefault(false)) - .Column("UseCulturePattern", c => c.WithDefault(false)) - .Column("DisplayAlias", c => c.WithLength(2048))); + SchemaBuilder.CreateTable("AutoroutePartRecord", table => table + .ContentPartVersionRecord() + .Column("CustomPattern", c => c.WithLength(2048)) + .Column("UseCustomPattern", c => c.WithDefault(false)) + .Column("UseCulturePattern", c => c.WithDefault(false)) + .Column("DisplayAlias", c => c.WithLength(2048))); ContentDefinitionManager.AlterPartDefinition("AutoroutePart", part => part .Attachable() .WithDescription("Adds advanced url configuration options to your content type to completely customize the url pattern for a content item.")); SchemaBuilder.AlterTable("AutoroutePartRecord", table => table - .CreateIndex("IDX_AutoroutePartRecord_DisplayAlias", "DisplayAlias") - ); + .CreateIndex("IDX_AutoroutePartRecord_DisplayAlias", "DisplayAlias")); - return 4; + CreateCulturePatterns(); + + return 5; } public int UpdateFrom1() { ContentDefinitionManager.AlterPartDefinition("AutoroutePart", part => part .WithDescription("Adds advanced url configuration options to your content type to completely customize the url pattern for a content item.")); + return 2; } public int UpdateFrom2() { - SchemaBuilder.AlterTable("AutoroutePartRecord", table => table - .CreateIndex("IDX_AutoroutePartRecord_DisplayAlias", "DisplayAlias") - ); + .CreateIndex("IDX_AutoroutePartRecord_DisplayAlias", "DisplayAlias")); return 3; } public int UpdateFrom3() { - SchemaBuilder.AlterTable("AutoroutePartRecord", table => table - .AddColumn("UseCulturePattern", c => c.WithDefault(false)) - ); + .AddColumn("UseCulturePattern", c => c.WithDefault(false))); return 4; } public int UpdateFrom4() { - // Adding some culture neutral patterns if they don't exist + CreateCulturePatterns(); + + return 5; + } + + + private void CreateCulturePatterns() { var autoroutePartDefinitions = ContentDefinitionManager.ListTypeDefinitions() - .Where(t => t.Parts.Any(p => p.PartDefinition.Name.Equals(typeof(AutoroutePart).Name))) - .Select(s => new { contentTypeName = s.Name, autoroutePart = s.Parts.First(x => x.PartDefinition.Name == "AutoroutePart") }); + .Where(type => type.Parts.Any(p => p.PartDefinition.Name == nameof(AutoroutePart))) + .Select(type => new { ContentTypeName = type.Name, AutoroutePart = type.Parts.First(x => x.PartDefinition.Name == nameof(AutoroutePart)) }); foreach (var partDefinition in autoroutePartDefinitions) { - var settingsDictionary = partDefinition.autoroutePart.Settings; + var settingsDictionary = partDefinition.AutoroutePart.Settings; var settings = settingsDictionary.GetModel(); - if (!settings.Patterns.Any(x => String.IsNullOrWhiteSpace(x.Culture))) { - string siteCulture = _cultureManager.GetSiteCulture(); + if (!settings.Patterns.Any(pattern => string.IsNullOrWhiteSpace(pattern.Culture))) { + var siteCulture = _cultureManager.GetSiteCulture(); List newPatterns = new List(); - if (settings.Patterns.Any(x => String.Equals(x.Culture, siteCulture, StringComparison.OrdinalIgnoreCase))) { - var siteCulturePatterns = settings.Patterns.Where(x => String.Equals(x.Culture, siteCulture, StringComparison.OrdinalIgnoreCase)).ToList(); - + var siteCulturePatterns = settings.Patterns + .Where(pattern => string.Equals(pattern.Culture, siteCulture, StringComparison.OrdinalIgnoreCase)).ToList(); + if (siteCulturePatterns.Any()) { foreach (RoutePattern pattern in siteCulturePatterns) { - newPatterns.Add(String.Format("{{\"Name\":\"{0}\",\"Pattern\":\"{1}\",\"Description\":\"{2}\"}}", pattern.Name, pattern.Pattern, pattern.Description)); + newPatterns.Add($"{{\"Name\":\"{pattern.Name}\",\"Pattern\":\"{pattern.Pattern}\",\"Description\":\"{pattern.Description}\"}}"); } } else { - newPatterns.Add(String.Format("{{\"Name\":\"{0}\",\"Pattern\":\"{1}\",\"Description\":\"{2}\"}}", "Title", "{Content.Slug}", "my-title")); + newPatterns.Add("{{\"Name\":\"Title\",\"Pattern\":\"{Content.Slug}\",\"Description\":\"my-title\"}}"); } - if (settingsDictionary.ContainsKey("AutorouteSettings.PatternDefinitions")) { - string oldPatterns = settingsDictionary["AutorouteSettings.PatternDefinitions"]; - if (oldPatterns.StartsWith("[") && oldPatterns.EndsWith("]")) - newPatterns.Add(oldPatterns.Substring(1, oldPatterns.Length - 2)); + if (settingsDictionary.TryGetValue("AutorouteSettings.PatternDefinitions", out var oldPatterns) && + oldPatterns.StartsWith("[") && oldPatterns.EndsWith("]")) { + newPatterns.Add(oldPatterns.Substring(1, oldPatterns.Length - 2)); } - ContentDefinitionManager.AlterTypeDefinition(partDefinition.contentTypeName, cfg => cfg - .WithPart("AutoroutePart", builder => builder - .WithSetting("AutorouteSettings.PatternDefinitions", "[" + String.Join(",", newPatterns) + "]") - )); + ContentDefinitionManager.AlterTypeDefinition(partDefinition.ContentTypeName, type => type + .WithPart(nameof(AutoroutePart), builder => builder + .WithSetting("AutorouteSettings.PatternDefinitions", "[" + string.Join(",", newPatterns) + "]"))); } } - - return 5; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Module.txt b/src/Orchard.Web/Modules/Orchard.Autoroute/Module.txt index cd073b38e98..41f656a065b 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Module.txt @@ -2,8 +2,8 @@ Name: Autoroute AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Description for the module Features: Orchard.Autoroute: diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Orchard.Autoroute.csproj b/src/Orchard.Web/Modules/Orchard.Autoroute/Orchard.Autoroute.csproj index 5daad31c8fa..85c1a131df5 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/Orchard.Autoroute.csproj +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Orchard.Autoroute.csproj @@ -12,8 +12,8 @@ Properties Orchard.Autoroute Orchard.Autoroute - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,9 @@ + + + true @@ -49,10 +52,12 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -67,29 +72,23 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -109,12 +108,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {475B6C45-B27C-438B-8966-908B9D6D1077} @@ -136,6 +135,7 @@ + @@ -168,7 +168,7 @@ - + 10.0 @@ -194,7 +194,7 @@ --> - + @@ -208,10 +208,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Autoroute/Properties/AssemblyInfo.cs index c8e79d52a2f..9b874c950b4 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Providers/SlugTokens.cs b/src/Orchard.Web/Modules/Orchard.Autoroute/Providers/SlugTokens.cs index 74896d58dd3..db4bff33f20 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/Providers/SlugTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Providers/SlugTokens.cs @@ -41,6 +41,7 @@ public void Evaluate(EvaluateContext context) { context.For("Content") // {Content.Slug} .Token("Slug", (content => content == null ? String.Empty : _slugService.Slugify(content))) + .Chain("Slug", "Text", (content => content == null ? String.Empty : _slugService.Slugify(content))) .Token("Path", (content => { var autoroutePart = content.As(); if (autoroutePart == null) { diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Services/AutorouteNoLockTableProvider.cs b/src/Orchard.Web/Modules/Orchard.Autoroute/Services/AutorouteNoLockTableProvider.cs new file mode 100644 index 00000000000..af85027bde5 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Services/AutorouteNoLockTableProvider.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using Orchard.Data.Providers; + +namespace Orchard.Autoroute.Services { + public class AutorouteNoLockTableProvider : INoLockTableProvider { + public IEnumerable GetTableNames() { + return new string[] { "Orchard_Autoroute_AutoroutePartRecord" }; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Services/AutorouteService.cs b/src/Orchard.Web/Modules/Orchard.Autoroute/Services/AutorouteService.cs index ff52a64e78d..01fb2ce4b5c 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/Services/AutorouteService.cs +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Services/AutorouteService.cs @@ -180,11 +180,13 @@ public RoutePattern GetDefaultPattern(string contentType, string culture) { } public void RemoveAliases(AutoroutePart part) { - _aliasService.Delete(part.Path, AliasSource); + if (part != null) { + _aliasService.Delete(part.Path, AliasSource); + } } public string GenerateUniqueSlug(AutoroutePart part, IEnumerable existingPaths) { - if (existingPaths == null || !existingPaths.Contains(part.Path)) + if (existingPaths == null || !existingPaths.Contains(part.Path, StringComparer.OrdinalIgnoreCase)) return part.Path; var version = existingPaths.Select(s => GetSlugVersion(part.Path, s)).OrderBy(i => i).LastOrDefault(); @@ -206,6 +208,39 @@ public bool IsPathValid(string slug) { } public bool ProcessPath(AutoroutePart part) { + // Try to get the path from the alias service + var pathRoute = _aliasService.Get(part.Path); + // If we got a route that matches that path + if (pathRoute != null) { + // and that route matches the route for the content item + var itemRoute = _contentManager.GetItemMetadata(part).DisplayRouteValues; + if (itemRoute != null + && pathRoute.Count == itemRoute.Count + && pathRoute.All(x => + // ensure value exists in the other dictionary + itemRoute[x.Key] != null + && x.Value.ToString() + // compare them as strings + .Equals(itemRoute[x.Key].ToString(), StringComparison.InvariantCultureIgnoreCase))) { + // then the path is fine as it is + return true; + } + // How does the above behave in different cases: + // 1. Part with new original path + // The route is not found among the aliases, so processing for it falls + // back to the original code below. + // 2. Path hasn't changed + // If the item is Published, the code above finds it among the aliases + // and this method ends. + // 3. Path is not original (there would be a collision) + // We find from the aliases the item the path points to. Comparing routes, + // we discover they do not match and fall back to the original code below. + // This code branch is basically a short circuit for the case where a ContentItem + // is being updated or published without changes to its path. Hence, it does not + // fix all issues we have with AutoroutePart and concurrency, but it is an + // attempt at mitigating them by preventing database operations in some cases. + } + var pathsLikeThis = GetSimilarPaths(part.Path).ToArray(); // Don't include *this* part in the list @@ -220,7 +255,6 @@ public bool ProcessPath(AutoroutePart part) { if (originalPath != newPath) return false; } - return true; } @@ -253,7 +287,8 @@ private string GetDefaultPatternIndex(string contentType, string culture) { private static int? GetSlugVersion(string path, string potentialConflictingPath) { int v; - var slugParts = potentialConflictingPath.Split(new[] { path }, StringSplitOptions.RemoveEmptyEntries); + // Matching needs to ignore case, so both paths are forced to lowercase. + var slugParts = potentialConflictingPath.ToLower().Split(new[] { path.ToLower() }, StringSplitOptions.RemoveEmptyEntries); if (slugParts.Length == 0) return 2; diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Services/HomeAliasService.cs b/src/Orchard.Web/Modules/Orchard.Autoroute/Services/HomeAliasService.cs index da86ac2bddf..3a945be21d7 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/Services/HomeAliasService.cs +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Services/HomeAliasService.cs @@ -91,7 +91,7 @@ private bool IsSameRoute(IDictionary a, RouteValueDictionary b) { return false; } - return a.Keys.All(x => String.Equals(a[x], b[x].ToString(), StringComparison.OrdinalIgnoreCase)); + return a.Keys.All(x => String.Equals(a[x], Convert.ToString(b[x]), StringComparison.OrdinalIgnoreCase)); } } } diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Settings/AutorouteSettings.cs b/src/Orchard.Web/Modules/Orchard.Autoroute/Settings/AutorouteSettings.cs index 75bc1a033de..4c8291b0adb 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/Settings/AutorouteSettings.cs +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Settings/AutorouteSettings.cs @@ -18,6 +18,7 @@ public class AutorouteSettings { public AutorouteSettings() { PerItemConfiguration = false; AllowCustomPattern = true; + AllowSetAsHomePage = true; UseCulturePattern = false; AutomaticAdjustmentOnEdit = false; PatternDefinitions = "[]"; @@ -27,6 +28,7 @@ public AutorouteSettings() { public bool PerItemConfiguration { get; set; } public bool AllowCustomPattern { get; set; } + public bool AllowSetAsHomePage { get; set; } public bool UseCulturePattern { get; set; } public bool AutomaticAdjustmentOnEdit { get; set; } public bool? IsDefault { get; set; } @@ -100,6 +102,7 @@ public List DefaultPatterns { public void Build(ContentTypePartDefinitionBuilder builder) { builder.WithSetting("AutorouteSettings.PerItemConfiguration", PerItemConfiguration.ToString(CultureInfo.InvariantCulture)); builder.WithSetting("AutorouteSettings.AllowCustomPattern", AllowCustomPattern.ToString(CultureInfo.InvariantCulture)); + builder.WithSetting("AutorouteSettings.AllowSetAsHomePage", AllowSetAsHomePage.ToString(CultureInfo.InvariantCulture)); builder.WithSetting("AutorouteSettings.UseCulturePattern", UseCulturePattern.ToString(CultureInfo.InvariantCulture)); builder.WithSetting("AutorouteSettings.AutomaticAdjustmentOnEdit", AutomaticAdjustmentOnEdit.ToString(CultureInfo.InvariantCulture)); builder.WithSetting("AutorouteSettings.PatternDefinitions", PatternDefinitions); diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Settings/AutorouteSettingsEvents.cs b/src/Orchard.Web/Modules/Orchard.Autoroute/Settings/AutorouteSettingsEvents.cs index fa369575fff..49b867b99ef 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/Settings/AutorouteSettingsEvents.cs +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Settings/AutorouteSettingsEvents.cs @@ -37,17 +37,15 @@ public override IEnumerable TypePartEditor(ContentTypePartDef List newPatterns = new List(); // Adding a null culture for the culture neutral pattern - List cultures = new List(); + var cultures = new List(); cultures.Add(null); cultures.AddRange(settings.SiteCultures); - - int current = 0; + foreach (string culture in cultures) { // Adding all existing patterns for the culture - foreach (RoutePattern routePattern in settings.Patterns.Where(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase))) { - newPatterns.Add(settings.Patterns[current]); - current++; - } + newPatterns.AddRange( + settings.Patterns.Where(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase)) + ); // Adding a pattern for each culture if there is none if (!settings.Patterns.Where(x => String.Equals(x.Culture, culture, StringComparison.OrdinalIgnoreCase)).Any()) { @@ -58,7 +56,7 @@ public override IEnumerable TypePartEditor(ContentTypePartDef newPatterns.Add(new RoutePattern { Culture = culture, Name = null, Description = null, Pattern = null }); // If the content type has no defaultPattern for autoroute, assign one - bool defaultPatternExists = false; + var defaultPatternExists = false; if (String.IsNullOrEmpty(culture)) defaultPatternExists = settings.DefaultPatterns.Any(x => String.IsNullOrEmpty(x.Culture)); else @@ -102,7 +100,7 @@ public override IEnumerable TypePartEditorUpdate(ContentTypeP //TODO need to add validations client and/or server side here // If some default pattern is an empty pattern set it to the first pattern for the language - List newDefaultPatterns = new List(); + var newDefaultPatterns = new List(); foreach (var defaultPattern in settings.DefaultPatterns) { RoutePattern correspondingPattern = null; @@ -125,7 +123,7 @@ public override IEnumerable TypePartEditorUpdate(ContentTypeP patterns.RemoveAll(p => String.IsNullOrWhiteSpace(p.Name) && String.IsNullOrWhiteSpace(p.Pattern) && String.IsNullOrWhiteSpace(p.Description)); // Adding a null culture for the culture neutral pattern - List cultures = new List(); + var cultures = new List(); cultures.Add(null); cultures.AddRange(settings.SiteCultures); diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Views/DefinitionTemplates/AutorouteSettings.cshtml b/src/Orchard.Web/Modules/Orchard.Autoroute/Views/DefinitionTemplates/AutorouteSettings.cshtml index ebc34592064..5f400d3886e 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/Views/DefinitionTemplates/AutorouteSettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Views/DefinitionTemplates/AutorouteSettings.cshtml @@ -15,7 +15,15 @@
    @Html.CheckBoxFor(m => m.AllowCustomPattern) - @T("Allow the user to change the pattern on each item") + @T("Allow the user to change the pattern on each item.") +
    + +
    +
    + @Html.CheckBoxFor(m => m.AllowSetAsHomePage) + + @T("Allow the user to set a content item of this type as the home page.") + @T("NOTE: Certain combinations of content type definitions and permission settings can create circumstances for non-Admin users with Dashboard access to remove the home page without the ability to set another one. Use this option with caution.")
    diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Views/EditorTemplates/Parts.Autoroute.Edit.cshtml b/src/Orchard.Web/Modules/Orchard.Autoroute/Views/EditorTemplates/Parts.Autoroute.Edit.cshtml index db6d9be356d..8e5d5f5ed16 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/Views/EditorTemplates/Parts.Autoroute.Edit.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Views/EditorTemplates/Parts.Autoroute.Edit.cshtml @@ -51,7 +51,7 @@
    @if (!Model.IsHomePage) { - if (AuthorizedFor(Permissions.SetHomePage)) { + if (AuthorizedFor(Permissions.SetHomePage) && Model.Settings.AllowSetAsHomePage) {
    @Html.CheckBoxFor(m => m.PromoteToHomePage) diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/Web.config b/src/Orchard.Web/Modules/Orchard.Autoroute/Web.config index 91ff0037561..7f4a0f97dc5 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/Web.config @@ -7,7 +7,7 @@ - + @@ -20,39 +20,58 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Autoroute/packages.config b/src/Orchard.Web/Modules/Orchard.Autoroute/packages.config index 6729ced4977..1c55d6960bb 100644 --- a/src/Orchard.Web/Modules/Orchard.Autoroute/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Autoroute/packages.config @@ -1,7 +1,8 @@  - - - - - \ No newline at end of file + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Controllers/MediaController.cs b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Controllers/MediaController.cs index 68c65ed2778..796e9ec0dfa 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Controllers/MediaController.cs +++ b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Controllers/MediaController.cs @@ -154,7 +154,7 @@ private ActionResult UpdateImplementation(CloudVideoPart part, string folderPath _transactionManager.Cancel(); Logger.Error(ex, "Error while saving cloud video item with ID {0}.", part.Id); - _notifier.Error(T("An error occurred while saving the cloud video item:\n{1}", ex.Message)); + _notifier.Error(T("An error occurred while saving the cloud video item:\n{0}", ex.Message)); } return RedirectToAction("Edit", new { id = part.Id }); diff --git a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Module.txt b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Module.txt index 581f7265c24..51266186d46 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: Microsoft Open Technologies, Inc Website: http://msopentech.com -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Provides integration of Microsoft Azure Media Services functionality into Orchard. Features: Orchard.Azure.MediaServices: diff --git a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Orchard.Azure.MediaServices.csproj b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Orchard.Azure.MediaServices.csproj index dfa962e0793..ab5b25bdeea 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Orchard.Azure.MediaServices.csproj +++ b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Orchard.Azure.MediaServices.csproj @@ -12,8 +12,8 @@ Properties Orchard.Azure.MediaServices Orchard.Azure.MediaServices - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -25,6 +25,9 @@ + + + true @@ -48,74 +51,78 @@ false - - ..\..\..\packages\FluentNHibernate.2.0.3.0\lib\net40\FluentNHibernate.dll - True + + ..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll - - ..\..\..\packages\HtmlAgilityPack.1.4.9\lib\Net45\HtmlAgilityPack.dll - True + + ..\..\..\packages\FluentNHibernate.3.1.0\lib\net461\FluentNHibernate.dll - - ..\..\..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll - True + + ..\..\..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll + + + ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll ..\..\..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll - True + + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll - - ..\..\..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll - True + + ..\..\..\packages\Microsoft.Data.Edm.5.8.4\lib\net40\Microsoft.Data.Edm.dll + + + ..\..\..\packages\Microsoft.Data.OData.5.8.4\lib\net40\Microsoft.Data.OData.dll + + + ..\..\..\packages\Microsoft.Data.Services.Client.5.8.4\lib\net40\Microsoft.Data.Services.Client.dll - - ..\..\..\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll - True + + ..\..\..\packages\Microsoft.IdentityModel.JsonWebTokens.5.7.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.dll - - ..\..\..\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll - True + + ..\..\..\packages\Microsoft.IdentityModel.Logging.5.7.0\lib\net461\Microsoft.IdentityModel.Logging.dll + + + ..\..\..\packages\Microsoft.IdentityModel.Tokens.5.7.0\lib\net461\Microsoft.IdentityModel.Tokens.dll ..\..\..\packages\TransientFaultHandling.Core.5.1.1209.1\lib\NET4\Microsoft.Practices.TransientFaultHandling.Core.dll - True ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True ..\..\..\packages\Microsoft.WindowsAzure.ConfigurationManager.3.1.0\lib\net40\Microsoft.WindowsAzure.Configuration.dll - True ..\..\..\packages\Orchard.WindowsAzure.Diagnostics.2.7.0.0\lib\Microsoft.WindowsAzure.Diagnostics.dll - True ..\..\..\packages\windowsazure.mediaservices.3.4.0.0\lib\net45\Microsoft.WindowsAzure.MediaServices.Client.dll - True ..\..\..\packages\windowsazure.mediaservices.3.4.0.0\lib\net45\Microsoft.WindowsAzure.MediaServices.Client.Common.BlobTransfer.dll - True ..\..\..\packages\windowsazure.mediaservices.3.4.0.0\lib\net45\Microsoft.WindowsAzure.MediaServices.Client.Common.FileEncryption.dll - True ..\..\..\packages\WindowsAzure.Storage.5.0.2\lib\net40\Microsoft.WindowsAzure.Storage.dll - True - - ..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True + + ..\..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll + + + ..\..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll - - ..\..\..\packages\NHibernate.4.0.1.4000\lib\net40\NHibernate.dll - True + + ..\..\..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll @@ -123,14 +130,15 @@ 3.5 - - ..\..\..\packages\System.IdentityModel.Tokens.Jwt.4.0.2.206221351\lib\net45\System.IdentityModel.Tokens.Jwt.dll - True + + ..\..\..\packages\System.IdentityModel.Tokens.Jwt.5.7.0\lib\net461\System.IdentityModel.Tokens.Jwt.dll - - ..\..\..\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll - True + + + + ..\..\..\packages\System.Spatial.5.8.4\lib\net40\System.Spatial.dll + @@ -138,29 +146,23 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -288,12 +290,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {73a7688a-5bd3-4f7e-adfa-ce36c5a10e3b} @@ -539,7 +541,8 @@ - + + @@ -575,7 +578,7 @@ --> - + @@ -589,7 +592,7 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False diff --git a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Properties/AssemblyInfo.cs index 074fbef69b4..f50601b8981 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Properties/AssemblyInfo.cs @@ -32,6 +32,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Scripts/Lib/dash.all.js b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Scripts/Lib/dash.all.js index 7bb86cd4245..6ed9dadbef5 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Scripts/Lib/dash.all.js +++ b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Scripts/Lib/dash.all.js @@ -1,5 +1,11 @@ +/* +** NOTE: This file is generated by Gulp and should not be edited directly! +** Any changes made directly to this file will be overwritten next time its asset group is processed by Gulp. +*/ + function X2JS(a,b,c){function d(a){var b=a.localName;return null==b&&(b=a.baseName),(null==b||""==b)&&(b=a.nodeName),b}function e(a){return a.prefix}function f(a){return"string"==typeof a?a.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/"):a}function g(a){return a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(///g,"/")}function h(f){if(f.nodeType==u.DOCUMENT_NODE){var i,j,k,l=f.firstChild;for(j=0,k=f.childNodes.length;k>j;j+=1)if(f.childNodes[j].nodeType!==u.COMMENT_NODE){l=f.childNodes[j];break}if(c)i=h(l);else{i={};var m=d(l);i[m]=h(l)}return i}if(f.nodeType==u.ELEMENT_NODE){var i=new Object;i.__cnt=0;for(var n=f.childNodes,o=0;ow;w++){var y=a[w];y.test.call(this,s.value)&&(v=y.converter.call(this,s.value))}i[b+s.name]=v}var z=e(f);return null!=z&&""!=z&&(i.__cnt++,i.__prefix=z),1==i.__cnt&&null!=i["#text"]&&(i=i["#text"]),null!=i["#text"]&&(i.__text=i["#text"],t&&(i.__text=g(i.__text)),delete i["#text"],delete i["#text_asArray"]),null!=i["#cdata-section"]&&(i.__cdata=i["#cdata-section"],delete i["#cdata-section"],delete i["#cdata-section_asArray"]),(null!=i.__text||null!=i.__cdata)&&(i.toString=function(){return(null!=this.__text?this.__text:"")+(null!=this.__cdata?this.__cdata:"")}),i}return f.nodeType==u.TEXT_NODE||f.nodeType==u.CDATA_SECTION_NODE?f.nodeValue:f.nodeType==u.COMMENT_NODE?null:void 0}function i(a,b,c,d){var e="<"+(null!=a&&null!=a.__prefix?a.__prefix+":":"")+b;if(null!=c)for(var f=0;f":">"}function j(a,b){return""}function k(a,b){return-1!==a.indexOf(b,a.length-b.length)}function l(a,b){return k(b.toString(),"_asArray")||0==b.toString().indexOf("_")||a[b]instanceof Function?!0:!1}function m(a){var b=0;if(a instanceof Object)for(var c in a)l(a,c)||b++;return b}function n(a){var b=[];if(a instanceof Object)for(var c in a)-1==c.toString().indexOf("__")&&0==c.toString().indexOf("_")&&b.push(c);return b}function o(a){var b="";return null!=a.__cdata&&(b+=""),null!=a.__text&&(b+=t?f(a.__text):a.__text),b}function p(a){var b="";return a instanceof Object?b+=o(a):null!=a&&(b+=t?f(a):a),b}function q(a,b,c){var d="";if(0==a.length)d+=i(a,b,c,!0);else for(var e=0;e0)for(var d in a)if(!l(a,d)){var e=a[d],f=n(e);if(null==e||void 0==e)b+=i(e,d,f,!0);else if(e instanceof Object)if(e instanceof Array)b+=q(e,d,f);else{var g=m(e);g>0||null!=e.__text||null!=e.__cdata?(b+=i(e,d,f,!1),b+=r(e),b+=j(e,d)):b+=i(e,d,f,!0)}else b+=i(e,d,f,!1),b+=p(e),b+=j(e,d)}return b+=p(a)}(null===b||void 0===b)&&(b="_"),(null===c||void 0===c)&&(c=!1);var s="1.0.11",t=!1,u={ELEMENT_NODE:1,TEXT_NODE:3,CDATA_SECTION_NODE:4,COMMENT_NODE:8,DOCUMENT_NODE:9};this.parseXmlString=function(a){var b;if(window.DOMParser){var c=new window.DOMParser;b=c.parseFromString(a,"text/xml")}else 0==a.indexOf("")+2)),b=new ActiveXObject("Microsoft.XMLDOM"),b.async="false",b.loadXML(a);return b},this.xml2json=function(a){return h(a)},this.xml_str2json=function(a){var b=this.parseXmlString(a);return this.xml2json(b)},this.json2xml_str=function(a){return r(a)},this.json2xml=function(a){var b=this.json2xml_str(a);return this.parseXmlString(b)},this.getVersion=function(){return s},this.escapeMode=function(a){t=a}}function ObjectIron(a){var b;for(b=[],i=0,len=a.length;len>i;i+=1)a[i].isRoot?b.push("root"):b.push(a[i].name);var c=function(a,b){var c;if(null!==a&&null!==b)for(c in a)a.hasOwnProperty(c)&&(b.hasOwnProperty(c)||(b[c]=a[c]))},d=function(a,b,d){var e,f,g,h,i;if(null!==a&&0!==a.length)for(e=0,f=a.length;f>e;e+=1)g=a[e],b.hasOwnProperty(g.name)&&(d.hasOwnProperty(g.name)?g.merge&&(h=b[g.name],i=d[g.name],"object"==typeof h&&"object"==typeof i?c(h,i):d[g.name]=null!=g.mergeFunction?g.mergeFunction(h,i):h+i):d[g.name]=b[g.name])},e=function(a,b){var c,f,g,h,i,j,k,l=a;if(null!==l.children&&0!==l.children.length)for(c=0,f=l.children.length;f>c;c+=1)if(j=l.children[c],b.hasOwnProperty(j.name))if(j.isArray)for(i=b[j.name+"_asArray"],g=0,h=i.length;h>g;g+=1)k=i[g],d(l.properties,b,k),e(j,k);else k=b[j.name],d(l.properties,b,k),e(j,k)},f=function(c){var d,g,h,i,j,k,l;if(null===c)return c;if("object"!=typeof c)return c;for(d=0,g=b.length;g>d;d+=1)"root"===b[d]&&(j=a[d],k=c,e(j,k));for(i in c)if(c.hasOwnProperty(i)){if(h=b.indexOf(i),-1!==h)if(j=a[h],j.isArray)for(l=c[i+"_asArray"],d=0,g=l.length;g>d;d+=1)k=l[d],e(j,k);else k=c[i],e(j,k);f(c[i])}return c};return{run:f}}if(function(a){a(void 0,Q={})}(function(a,b){function c(a,b){b.stack&&"object"==typeof a&&null!==a&&a.stack&&-1===a.stack.indexOf(N)&&(a.stack=d(a.stack)+"\n"+N+"\n"+d(b.stack))}function d(a){for(var a=a.split("\n"),b=[],c=0;c=x&&T>=f}else d=!1;!d&&!(-1!==e.indexOf("(module.js:")||-1!==e.indexOf("(node.js:"))&&b.push(e)}return b.join("\n")}function e(){if(Error.captureStackTrace){var a,b,c=Error.prepareStackTrace;return Error.prepareStackTrace=function(c,d){a=d[1].getFileName(),b=d[1].getLineNumber()},Error().stack,Error.prepareStackTrace=c,w=a,b}}function f(a,b,c){return function(){return"undefined"!=typeof console&&"function"==typeof console.warn&&console.warn(b+" is deprecated, use "+c+" instead.",Error("").stack),a.apply(a,arguments)}}function g(){function a(a){c&&(b=n(a),H(c,function(a,c){A(function(){b.promiseDispatch.apply(b,c)})},void 0),d=c=void 0)}var b,c=[],d=[],e=K(g.prototype),f=K(h.prototype);return f.promiseDispatch=function(a,e,f){var g=G(arguments);c?(c.push(g),"when"===e&&f[1]&&d.push(f[1])):A(function(){b.promiseDispatch.apply(b,g)})},f.valueOf=function(){return c?f:b.valueOf()},Error.captureStackTrace&&(Error.captureStackTrace(f,g),f.stack=f.stack.substring(f.stack.indexOf("\n")+1)),z(f),e.promise=f,e.resolve=a,e.reject=function(b){a(m(b))},e.notify=function(a){c&&H(d,function(b,c){A(function(){c(a)})},void 0)},e}function h(a,b,c,d){void 0===b&&(b=function(a){return m(Error("Promise does not support operation: "+a))});var e=K(h.prototype);return e.promiseDispatch=function(c,d,f){var g;try{g=a[d]?a[d].apply(e,f):b.call(e,d,f)}catch(h){g=m(h)}c&&c(g)},c&&(e.valueOf=c),d&&(e.exception=d),z(e),e}function i(a){return j(a)?a.valueOf():a}function j(a){return a&&"function"==typeof a.promiseDispatch}function k(a){return!j(i(a))}function l(a){return a=i(a),j(a)&&"exception"in a}function m(a){var a=a||Error(),b=h({when:function(b){if(b){var c=I(P,this);-1!==c&&(Q.splice(c,1),P.splice(c,1))}return b?b(a):m(a)}},function(){return m(a)},function(){return this},a);return!O&&"undefined"!=typeof window&&!window.Touch&&window.console&&console.log("Should be empty:",Q),O=!0,P.push(b),Q.push(a),b}function n(a){if(j(a))return a;if((a=i(a))&&"function"==typeof a.then){var b=g();return a.then(b.resolve,b.reject,b.notify),b.promise}return h({when:function(){return a},get:function(b){return a[b]},put:function(b,c){return a[b]=c,a},del:function(b){return delete a[b],a},post:function(b,c){return a[b].apply(a,c)},apply:function(b){return a.apply(void 0,b)},keys:function(){return L(a)}},void 0,function(){return a})}function o(a,b,d,e){function f(a){try{return b?b(a):a}catch(c){return m(c)}}function h(a){if(d){c(a,k);try{return d(a)}catch(b){return m(b)}}return m(a)}var i=g(),j=!1,k=n(a);return A(function(){k.promiseDispatch(function(a){j||(j=!0,i.resolve(f(a)))},"when",[function(a){j||(j=!0,i.resolve(h(a)))}])}),k.promiseDispatch(void 0,"when",[void 0,function(a){i.notify(e?e(a):a)}]),i.promise}function p(a,b,c){return o(a,function(a){return t(a).then(function(a){return b.apply(void 0,a)},c)},c)}function q(a,b,c){var d=g();return A(function(){n(a).promiseDispatch(d.resolve,b,c)}),d.promise}function r(a){return function(b){var c=G(arguments,1);return q(b,a,c)}}function s(a){var b=G(arguments,1);return S(a,b)}function t(a){return o(a,function(a){var b=a.length;if(0===b)return n(a);var c=g();return H(a,function(d,e,f){k(e)?(a[f]=i(e),0===--b&&c.resolve(a)):o(e,function(d){a[f]=d,0===--b&&c.resolve(a)}).fail(c.reject)},void 0),c.promise})}function u(a,b){return o(a,void 0,b)}function v(a,b){var c=G(arguments,2),d=g();return c.push(d.makeNodeResolver()),R(a,b,c).fail(d.reject),d.promise}var w,x=e(),y=function(){},z=Object.freeze||y;"undefined"!=typeof cajaVM&&(z=cajaVM.def);var A;if("undefined"!=typeof process)A=process.nextTick;else if("function"==typeof setImmediate)A=setImmediate;else if("undefined"!=typeof MessageChannel){var B=new MessageChannel,C={},D=C;B.port1.onmessage=function(){C=C.next;var a=C.task;delete C.task,a()},A=function(a){D=D.next={task:a},B.port2.postMessage(0)}}else A=function(a){setTimeout(a,0)};var E;Function.prototype.bind?(E=Function.prototype.bind,E=E.bind(E.call)):E=function(a){return function(){return a.call.apply(a,arguments)}};var F,G=E(Array.prototype.slice),H=E(Array.prototype.reduce||function(a,b){var c=0,d=this.length;if(1===arguments.length)for(;;){if(c in this){b=this[c++];break}if(++c>=d)throw new TypeError}for(;d>c;c++)c in this&&(b=a(b,this[c],c));return b}),I=E(Array.prototype.indexOf||function(a){for(var b=0;b2?a.resolve(G(arguments,1)):a.resolve(c)}},b.promise=function(a){var b=g();return s(a,b.resolve,b.reject,b.notify).fail(b.reject),b.promise},b.makePromise=h,h.prototype.then=function(a,b,c){return o(this,a,b,c)},h.prototype.thenResolve=function(a){return o(this,function(){return a})},H("isResolved isFulfilled isRejected dispatch when spread get put del post send invoke keys fapply fcall fbind all allResolved timeout delay catch finally fail fin progress end done nfcall nfapply nfbind ncall napply nbind npost nsend ninvoke nend nodeify".split(" "),function(a,c){h.prototype[c]=function(){return b[c].apply(b,[this].concat(G(arguments)))}},void 0),h.prototype.toSource=function(){return this.toString()},h.prototype.toString=function(){return"[object Promise]"},z(h.prototype),b.nearer=i,b.isPromise=j,b.isResolved=function(a){return k(a)||l(a)},b.isFulfilled=k,b.isRejected=l;var O,P=[],Q=[];b.reject=m,b.resolve=n,b.master=function(a){return h({isDef:function(){}},function(b,c){return q(a,b,c)},function(){return i(a)})},b.when=o,b.spread=p,b.async=function(a){return function(){function b(a,b){var f;try{f=c[a](b)}catch(g){return"[object StopIteration]"===M(g)||g instanceof F?g.value:m(g)}return o(f,d,e)}var c=a.apply(this,arguments),d=b.bind(b,"send"),e=b.bind(b,"throw");return d()}},b["return"]=function(a){throw new F(a)},b.promised=function(a){return function(){return p([this,t(arguments)],function(b,c){return a.apply(b,c)})}},b.dispatch=q,b.dispatcher=r,b.get=r("get"),b.put=r("put"),b["delete"]=b.del=r("del");var R=b.post=r("post");b.send=function(a,b){var c=G(arguments,2);return R(a,b,c)},b.invoke=f(b.send,"invoke","send");var S=b.fapply=r("apply");b["try"]=s,b.fcall=s,b.fbind=function(a){var b=G(arguments,1);return function(){var c=b.concat(G(arguments));return S(a,c)}},b.keys=r("keys"),b.all=t,b.allResolved=function(a){return o(a,function(a){return o(t(J(a,function(a){return o(a,y,y)})),function(){return J(a,n)})})},b["catch"]=b.fail=u,b.progress=function(a,b){return o(a,void 0,void 0,b)},b["finally"]=b.fin=function(a,b){return o(a,function(a){return o(b(),function(){return a})},function(a){return o(b(),function(){return m(a)})})},b.done=function(a,d,e,f){d=d||e||f?o(a,d,e,f):a,u(d,function(d){A(function(){if(c(d,a),!b.onerror)throw d;b.onerror(d)})})},b.timeout=function(a,b){var c=g(),d=setTimeout(function(){c.reject(Error("Timed out after "+b+" ms"))},b);return o(a,function(a){clearTimeout(d),c.resolve(a)},function(a){clearTimeout(d),c.reject(a)}),c.promise},b.delay=function(a,b){void 0===b&&(b=a,a=void 0);var c=g();return setTimeout(function(){c.resolve(a)},b),c.promise},b.nfapply=function(a,b){var c=G(b),d=g();return c.push(d.makeNodeResolver()),S(a,c).fail(d.reject),d.promise},b.nfcall=function(a){var b=G(arguments,1),c=g();return b.push(c.makeNodeResolver()),S(a,b).fail(c.reject),c.promise},b.nfbind=function(a){var b=G(arguments,1);return function(){var c=b.concat(G(arguments)),d=g();return c.push(d.makeNodeResolver()),S(a,c).fail(d.reject),d.promise}},b.npost=function(a,b,c){var c=G(c),d=g();return c.push(d.makeNodeResolver()),R(a,b,c).fail(d.reject),d.promise},b.nsend=v,b.ninvoke=f(v,"ninvoke","nsend"),b.nodeify=function(a,b){return b?(a.then(function(a){A(function(){b(null,a)})},function(a){A(function(){b(a)})}),void 0):a};var T=e()}),function(a){"use strict";var b={VERSION:"0.5.3"};b.System=function(){this._mappings={},this._outlets={},this._handlers={},this.strictInjections=!0,this.autoMapOutlets=!1,this.postInjectionHook="setup"},b.System.prototype={_createAndSetupInstance:function(a,b){var c=new b;return this.injectInto(c,a),c},_retrieveFromCacheOrCreate:function(a,b){"undefined"==typeof b&&(b=!1);var c;if(!this._mappings.hasOwnProperty(a))throw new Error(1e3);var d=this._mappings[a];return!b&&d.isSingleton?(null==d.object&&(d.object=this._createAndSetupInstance(a,d.clazz)),c=d.object):c=d.clazz?this._createAndSetupInstance(a,d.clazz):d.object,c},mapOutlet:function(a,b,c){if("undefined"==typeof a)throw new Error(1010);return b=b||"global",c=c||a,this._outlets.hasOwnProperty(b)||(this._outlets[b]={}),this._outlets[b][c]=a,this},getObject:function(a){if("undefined"==typeof a)throw new Error(1020);return this._retrieveFromCacheOrCreate(a)},mapValue:function(a,b){if("undefined"==typeof a)throw new Error(1030);return this._mappings[a]={clazz:null,object:b,isSingleton:!0},this.autoMapOutlets&&this.mapOutlet(a),this.hasMapping(a)&&this.injectInto(b,a),this},hasMapping:function(a){if("undefined"==typeof a)throw new Error(1040);return this._mappings.hasOwnProperty(a)},mapClass:function(a,b){if("undefined"==typeof a)throw new Error(1050);if("undefined"==typeof b)throw new Error(1051);return this._mappings[a]={clazz:b,object:null,isSingleton:!1},this.autoMapOutlets&&this.mapOutlet(a),this},mapSingleton:function(a,b){if("undefined"==typeof a)throw new Error(1060);if("undefined"==typeof b)throw new Error(1061);return this._mappings[a]={clazz:b,object:null,isSingleton:!0},this.autoMapOutlets&&this.mapOutlet(a),this},instantiate:function(a){if("undefined"==typeof a)throw new Error(1070);return this._retrieveFromCacheOrCreate(a,!0)},injectInto:function(a,b){if("undefined"==typeof a)throw new Error(1080);if("object"==typeof a){var c=[];this._outlets.hasOwnProperty("global")&&c.push(this._outlets.global),"undefined"!=typeof b&&this._outlets.hasOwnProperty(b)&&c.push(this._outlets[b]);for(var d in c){var e=c[d];for(var f in e){var g=e[f];(!this.strictInjections||f in a)&&(a[f]=this.getObject(g))}}"setup"in a&&a.setup.call(a)}return this},unmap:function(a){if("undefined"==typeof a)throw new Error(1090);return delete this._mappings[a],this},unmapOutlet:function(a,b){if("undefined"==typeof a)throw new Error(1100);if("undefined"==typeof b)throw new Error(1101);return delete this._outlets[a][b],this},mapHandler:function(a,b,c,d,e){if("undefined"==typeof a)throw new Error(1110);return b=b||"global",c=c||a,"undefined"==typeof d&&(d=!1),"undefined"==typeof e&&(e=!1),this._handlers.hasOwnProperty(a)||(this._handlers[a]={}),this._handlers[a].hasOwnProperty(b)||(this._handlers[a][b]=[]),this._handlers[a][b].push({handler:c,oneShot:d,passEvent:e}),this},unmapHandler:function(a,b,c){if("undefined"==typeof a)throw new Error(1120);if(b=b||"global",c=c||a,this._handlers.hasOwnProperty(a)&&this._handlers[a].hasOwnProperty(b)){var d=this._handlers[a][b];for(var e in d){var f=d[e];if(f.handler===c){d.splice(e,1);break}}}return this},notify:function(a){if("undefined"==typeof a)throw new Error(1130);var b=Array.prototype.slice.call(arguments),c=b.slice(1);if(this._handlers.hasOwnProperty(a)){var d=this._handlers[a];for(var e in d){var f,g=d[e];"global"!==e&&(f=this.getObject(e));var h,i,j=[];for(h=0,i=g.length;i>h;h++){var k,l=g[h];k=f&&"string"==typeof l.handler?f[l.handler]:l.handler,l.oneShot&&j.unshift(h),l.passEvent?k.apply(f,b):k.apply(f,c)}for(h=0,i=j.length;i>h;h++)g.splice(j[h],1)}}return this}},a.dijon=b}(this),"undefined"==typeof utils)var utils={};"undefined"==typeof utils.Math&&(utils.Math={}),utils.Math.to64BitNumber=function(a,b){var c,d,e;return c=new goog.math.Long(0,b),d=new goog.math.Long(a,0),e=c.add(d),e.toNumber()},goog={},goog.math={},goog.math.Long=function(a,b){this.low_=0|a,this.high_=0|b},goog.math.Long.IntCache_={},goog.math.Long.fromInt=function(a){if(a>=-128&&128>a){var b=goog.math.Long.IntCache_[a];if(b)return b}var c=new goog.math.Long(0|a,0>a?-1:0);return a>=-128&&128>a&&(goog.math.Long.IntCache_[a]=c),c},goog.math.Long.fromNumber=function(a){return isNaN(a)||!isFinite(a)?goog.math.Long.ZERO:a<=-goog.math.Long.TWO_PWR_63_DBL_?goog.math.Long.MIN_VALUE:a+1>=goog.math.Long.TWO_PWR_63_DBL_?goog.math.Long.MAX_VALUE:0>a?goog.math.Long.fromNumber(-a).negate():new goog.math.Long(0|a%goog.math.Long.TWO_PWR_32_DBL_,0|a/goog.math.Long.TWO_PWR_32_DBL_)},goog.math.Long.fromBits=function(a,b){return new goog.math.Long(a,b)},goog.math.Long.fromString=function(a,b){if(0==a.length)throw Error("number format error: empty string");var c=b||10;if(2>c||c>36)throw Error("radix out of range: "+c);if("-"==a.charAt(0))return goog.math.Long.fromString(a.substring(1),c).negate();if(a.indexOf("-")>=0)throw Error('number format error: interior "-" character: '+a);for(var d=goog.math.Long.fromNumber(Math.pow(c,8)),e=goog.math.Long.ZERO,f=0;fg){var i=goog.math.Long.fromNumber(Math.pow(c,g));e=e.multiply(i).add(goog.math.Long.fromNumber(h))}else e=e.multiply(d),e=e.add(goog.math.Long.fromNumber(h))}return e},goog.math.Long.TWO_PWR_16_DBL_=65536,goog.math.Long.TWO_PWR_24_DBL_=1<<24,goog.math.Long.TWO_PWR_32_DBL_=goog.math.Long.TWO_PWR_16_DBL_*goog.math.Long.TWO_PWR_16_DBL_,goog.math.Long.TWO_PWR_31_DBL_=goog.math.Long.TWO_PWR_32_DBL_/2,goog.math.Long.TWO_PWR_48_DBL_=goog.math.Long.TWO_PWR_32_DBL_*goog.math.Long.TWO_PWR_16_DBL_,goog.math.Long.TWO_PWR_64_DBL_=goog.math.Long.TWO_PWR_32_DBL_*goog.math.Long.TWO_PWR_32_DBL_,goog.math.Long.TWO_PWR_63_DBL_=goog.math.Long.TWO_PWR_64_DBL_/2,goog.math.Long.ZERO=goog.math.Long.fromInt(0),goog.math.Long.ONE=goog.math.Long.fromInt(1),goog.math.Long.NEG_ONE=goog.math.Long.fromInt(-1),goog.math.Long.MAX_VALUE=goog.math.Long.fromBits(-1,2147483647),goog.math.Long.MIN_VALUE=goog.math.Long.fromBits(0,-2147483648),goog.math.Long.TWO_PWR_24_=goog.math.Long.fromInt(1<<24),goog.math.Long.prototype.toInt=function(){return this.low_},goog.math.Long.prototype.toNumber=function(){return this.high_*goog.math.Long.TWO_PWR_32_DBL_+this.getLowBitsUnsigned()},goog.math.Long.prototype.toString=function(a){var b=a||10;if(2>b||b>36)throw Error("radix out of range: "+b);if(this.isZero())return"0";if(this.isNegative()){if(this.equals(goog.math.Long.MIN_VALUE)){var c=goog.math.Long.fromNumber(b),d=this.div(c),e=d.multiply(c).subtract(this);return d.toString(b)+e.toInt().toString(b)}return"-"+this.negate().toString(b)}for(var f=goog.math.Long.fromNumber(Math.pow(b,6)),e=this,g="";;){var h=e.div(f),i=e.subtract(h.multiply(f)).toInt(),j=i.toString(b);if(e=h,e.isZero())return j+g;for(;j.length<6;)j="0"+j;g=""+j+g}},goog.math.Long.prototype.getHighBits=function(){return this.high_},goog.math.Long.prototype.getLowBits=function(){return this.low_},goog.math.Long.prototype.getLowBitsUnsigned=function(){return this.low_>=0?this.low_:goog.math.Long.TWO_PWR_32_DBL_+this.low_},goog.math.Long.prototype.getNumBitsAbs=function(){if(this.isNegative())return this.equals(goog.math.Long.MIN_VALUE)?64:this.negate().getNumBitsAbs();for(var a=0!=this.high_?this.high_:this.low_,b=31;b>0&&0==(a&1<0},goog.math.Long.prototype.greaterThanOrEqual=function(a){return this.compare(a)>=0},goog.math.Long.prototype.compare=function(a){if(this.equals(a))return 0;var b=this.isNegative(),c=a.isNegative();return b&&!c?-1:!b&&c?1:this.subtract(a).isNegative()?-1:1},goog.math.Long.prototype.negate=function(){return this.equals(goog.math.Long.MIN_VALUE)?goog.math.Long.MIN_VALUE:this.not().add(goog.math.Long.ONE)},goog.math.Long.prototype.add=function(a){var b=this.high_>>>16,c=65535&this.high_,d=this.low_>>>16,e=65535&this.low_,f=a.high_>>>16,g=65535&a.high_,h=a.low_>>>16,i=65535&a.low_,j=0,k=0,l=0,m=0;return m+=e+i,l+=m>>>16,m&=65535,l+=d+h,k+=l>>>16,l&=65535,k+=c+g,j+=k>>>16,k&=65535,j+=b+f,j&=65535,goog.math.Long.fromBits(l<<16|m,j<<16|k)},goog.math.Long.prototype.subtract=function(a){return this.add(a.negate())},goog.math.Long.prototype.multiply=function(a){if(this.isZero())return goog.math.Long.ZERO;if(a.isZero())return goog.math.Long.ZERO;if(this.equals(goog.math.Long.MIN_VALUE))return a.isOdd()?goog.math.Long.MIN_VALUE:goog.math.Long.ZERO;if(a.equals(goog.math.Long.MIN_VALUE))return this.isOdd()?goog.math.Long.MIN_VALUE:goog.math.Long.ZERO;if(this.isNegative())return a.isNegative()?this.negate().multiply(a.negate()):this.negate().multiply(a).negate();if(a.isNegative())return this.multiply(a.negate()).negate();if(this.lessThan(goog.math.Long.TWO_PWR_24_)&&a.lessThan(goog.math.Long.TWO_PWR_24_))return goog.math.Long.fromNumber(this.toNumber()*a.toNumber());var b=this.high_>>>16,c=65535&this.high_,d=this.low_>>>16,e=65535&this.low_,f=a.high_>>>16,g=65535&a.high_,h=a.low_>>>16,i=65535&a.low_,j=0,k=0,l=0,m=0;return m+=e*i,l+=m>>>16,m&=65535,l+=d*i,k+=l>>>16,l&=65535,l+=e*h,k+=l>>>16,l&=65535,k+=c*i,j+=k>>>16,k&=65535,k+=d*h,j+=k>>>16,k&=65535,k+=e*g,j+=k>>>16,k&=65535,j+=b*i+c*h+d*g+e*f,j&=65535,goog.math.Long.fromBits(l<<16|m,j<<16|k)},goog.math.Long.prototype.div=function(a){if(a.isZero())throw Error("division by zero");if(this.isZero())return goog.math.Long.ZERO;if(this.equals(goog.math.Long.MIN_VALUE)){if(a.equals(goog.math.Long.ONE)||a.equals(goog.math.Long.NEG_ONE))return goog.math.Long.MIN_VALUE;if(a.equals(goog.math.Long.MIN_VALUE))return goog.math.Long.ONE;var b=this.shiftRight(1),c=b.div(a).shiftLeft(1);if(c.equals(goog.math.Long.ZERO))return a.isNegative()?goog.math.Long.ONE:goog.math.Long.NEG_ONE;var d=this.subtract(a.multiply(c)),e=c.add(d.div(a));return e}if(a.equals(goog.math.Long.MIN_VALUE))return goog.math.Long.ZERO;if(this.isNegative())return a.isNegative()?this.negate().div(a.negate()):this.negate().div(a).negate();if(a.isNegative())return this.div(a.negate()).negate();for(var f=goog.math.Long.ZERO,d=this;d.greaterThanOrEqual(a);){for(var c=Math.max(1,Math.floor(d.toNumber()/a.toNumber())),g=Math.ceil(Math.log(c)/Math.LN2),h=48>=g?1:Math.pow(2,g-48),i=goog.math.Long.fromNumber(c),j=i.multiply(a);j.isNegative()||j.greaterThan(d);)c-=h,i=goog.math.Long.fromNumber(c),j=i.multiply(a);i.isZero()&&(i=goog.math.Long.ONE),f=f.add(i),d=d.subtract(j)}return f},goog.math.Long.prototype.modulo=function(a){return this.subtract(this.div(a).multiply(a))},goog.math.Long.prototype.not=function(){return goog.math.Long.fromBits(~this.low_,~this.high_)},goog.math.Long.prototype.and=function(a){return goog.math.Long.fromBits(this.low_&a.low_,this.high_&a.high_)},goog.math.Long.prototype.or=function(a){return goog.math.Long.fromBits(this.low_|a.low_,this.high_|a.high_)},goog.math.Long.prototype.xor=function(a){return goog.math.Long.fromBits(this.low_^a.low_,this.high_^a.high_)},goog.math.Long.prototype.shiftLeft=function(a){if(a&=63,0==a)return this;var b=this.low_;if(32>a){var c=this.high_;return goog.math.Long.fromBits(b<>>32-a)}return goog.math.Long.fromBits(0,b<a){var c=this.low_;return goog.math.Long.fromBits(c>>>a|b<<32-a,b>>a)}return goog.math.Long.fromBits(b>>a-32,b>=0?0:-1)},goog.math.Long.prototype.shiftRightUnsigned=function(a){if(a&=63,0==a)return this;var b=this.high_;if(32>a){var c=this.low_;return goog.math.Long.fromBits(c>>>a|b<<32-a,b>>>a)}return 32==a?goog.math.Long.fromBits(b,0):goog.math.Long.fromBits(b>>>a-32,0)};var UTF8={};UTF8.encode=function(a){for(var b=[],c=0;cd?b.push(d):2048>d?(b.push(192|d>>6),b.push(128|63&d)):65536>d?(b.push(224|d>>12),b.push(128|63&d>>6),b.push(128|63&d)):(b.push(240|d>>18),b.push(128|63&d>>12),b.push(128|63&d>>6),b.push(128|63&d))}return b},UTF8.decode=function(a){for(var b=[],c=0;cd||(224>d?(d=(31&d)<<6,d|=63&a[c++]):240>d?(d=(15&d)<<12,d|=(63&a[c++])<<6,d|=63&a[c++]):(d=(7&d)<<18,d|=(63&a[c++])<<12,d|=(63&a[c++])<<6,d|=63&a[c++])),b.push(String.fromCharCode(d))}return b.join("")};var BASE64={};if(function(b){var c=function(a){for(var c=0,d=[],e=0|a.length/3;0>18)),d.push(b.charAt(63&f>>12)),d.push(b.charAt(63&f>>6)),d.push(b.charAt(63&f))}if(2==a.length-c){var f=(a[c]<<16)+(a[c+1]<<8);d.push(b.charAt(63&f>>18)),d.push(b.charAt(63&f>>12)),d.push(b.charAt(63&f>>6)),d.push("=")}else if(1==a.length-c){var f=a[c]<<16;d.push(b.charAt(63&f>>18)),d.push(b.charAt(63&f>>12)),d.push("==")}return d.join("")},d=function(){for(var a=[],c=0;cf;f+=1)l=m.getInt8(o),j+=String.fromCharCode(l),o+=1;"moof"!==j&&"traf"!==j&&"sidx"!==j?o+=k-8:"sidx"===j&&(o-=8)}if(e=m.getUint32(o,!1)+o,e>a.byteLength)throw"sidx terminates after array buffer";for(n.version=m.getUint8(o+8),o+=12,n.timescale=m.getUint32(o+4,!1),o+=8,0===n.version?(n.earliest_presentation_time=m.getUint32(o,!1),n.first_offset=m.getUint32(o+4,!1),o+=8):(n.earliest_presentation_time=utils.Math.to64BitNumber(m.getUint32(o+4,!1),m.getUint32(o,!1)),n.first_offset=(m.getUint32(o+8,!1)<<32)+m.getUint32(o+12,!1),o+=16),n.first_offset+=e+(b||0),n.reference_count=m.getUint16(o+2,!1),o+=4,n.references=[],c=n.first_offset,d=n.earliest_presentation_time,f=0;f>>31,h=2147483647&h,i=m.getUint32(o+4,!1),o+=12,n.references.push({size:h,type:g,offset:c,duration:i,time:d,timescale:n.timescale}),c+=h,d+=i;if(o!==e)throw"Error: final pos "+o+" differs from SIDX end "+e;return n},b=function(b,c,d){var e,f,g,h,i,j,k,l;for(e=a.call(this,b,d),f=e.references,g=[],i=0,j=f.length;j>i;i+=1)h=new Dash.vo.Segment,h.duration=f[i].duration,h.media=c,h.startTime=f[i].time,h.timescale=f[i].timescale,k=f[i].offset,l=f[i].offset+f[i].size-1,h.mediaRange=k+"-"+l,g.push(h);return this.debug.log("Parsed SIDX box: "+g.length+" segments."),Q.when(g)},c=function(a,b){var d,e,f,g,h,i,j,k=Q.defer(),l=new DataView(a),m=0,n="",o=0,p=!1,q=this;for(q.debug.log("Searching for initialization.");"moov"!==n&&mg;g+=1)h=l.getInt8(m),n+=String.fromCharCode(h),m+=1;"moov"!==n&&(m+=o-8)}return f=l.byteLength-m,"moov"!==n?(q.debug.log("Loading more bytes to find initialization."),b.range.start=0,b.range.end=b.bytesLoaded+b.bytesToLoad,i=new XMLHttpRequest,i.onloadend=function(){p||k.reject("Error loading initialization.")},i.onload=function(){p=!0,b.bytesLoaded=b.range.end,c.call(q,i.response).then(function(a){k.resolve(a)})},i.onerror=function(){k.reject("Error loading initialization.")},i.open("GET",b.url),i.responseType="arraybuffer",i.setRequestHeader("Range","bytes="+b.range.start+"-"+b.range.end),i.send(null)):(d=m-8,e=d+o-1,j=d+"-"+e,q.debug.log("Found the initialization. Range: "+j),k.resolve(j)),k.promise},d=function(a){var b=Q.defer(),d=new XMLHttpRequest,e=!0,f=this,g={url:a,range:{},searching:!1,bytesLoaded:0,bytesToLoad:1500,request:d};return f.debug.log("Start searching for initialization."),g.range.start=0,g.range.end=g.bytesToLoad,d.onload=function(){d.status<200||d.status>299||(e=!1,g.bytesLoaded=g.range.end,c.call(f,d.response,g).then(function(a){b.resolve(a)}))},d.onloadend=d.onerror=function(){e&&(e=!1,f.errHandler.downloadError("initialization",g.url,d),b.reject(d))},d.open("GET",g.url),d.responseType="arraybuffer",d.setRequestHeader("Range","bytes="+g.range.start+"-"+g.range.end),d.send(null),f.debug.log("Perform init search: "+g.url),b.promise},e=function(a,c){var d,f,g,h,i,j,k,l,m=Q.defer(),n=new DataView(a),o=new XMLHttpRequest,p=0,q="",r=0,s=!0,t=!1,u=this;for(u.debug.log("Searching for SIDX box."),u.debug.log(c.bytesLoaded+" bytes loaded.");"sidx"!==q&&pi;i+=1)j=n.getInt8(p),q+=String.fromCharCode(j),p+=1;"sidx"!==q&&(p+=r-8)}if(d=n.byteLength-p,"sidx"!==q)m.reject();else if(r-8>d)u.debug.log("Found SIDX but we don't have all of it."),c.range.start=0,c.range.end=c.bytesLoaded+(r-d),o.onload=function(){o.status<200||o.status>299||(s=!1,c.bytesLoaded=c.range.end,e.call(u,o.response,c).then(function(a){m.resolve(a)}))},o.onloadend=o.onerror=function(){s&&(s=!1,u.errHandler.downloadError("SIDX",c.url,o),m.reject(o))},o.open("GET",c.url),o.responseType="arraybuffer",o.setRequestHeader("Range","bytes="+c.range.start+"-"+c.range.end),o.send(null);else if(c.range.start=p-8,c.range.end=c.range.start+r,u.debug.log("Found the SIDX box. Start: "+c.range.start+" | End: "+c.range.end),f=new ArrayBuffer(c.range.end-c.range.start),h=new Uint8Array(f),g=new Uint8Array(a,c.range.start,c.range.end-c.range.start),h.set(g),k=this.parseSIDX.call(this,f,c.range.start),l=k.references,null!==l&&void 0!==l&&l.length>0&&(t=1===l[0].type),t){u.debug.log("Initiate multiple SIDX load.");var v,w,x,y,z,A,B=[];for(v=0,w=l.length;w>v;v+=1)x=l[v].offset,y=l[v].offset+l[v].size-1,z=x+"-"+y,B.push(this.loadSegments.call(u,c.url,z));Q.all(B).then(function(a){for(A=[],v=0,w=a.length;w>v;v+=1)A=A.concat(a[v]);m.resolve(A)},function(a){m.reject(a)})}else u.debug.log("Parsing segments from SIDX."),b.call(u,f,c.url,c.range.start).then(function(a){m.resolve(a)});return m.promise},f=function(a,c){var d,f=Q.defer(),g=new XMLHttpRequest,h=!0,i=this,j={url:a,range:{},searching:!1,bytesLoaded:0,bytesToLoad:1500,request:g};return null===c?(i.debug.log("No known range for SIDX request."),j.searching=!0,j.range.start=0,j.range.end=j.bytesToLoad):(d=c.split("-"),j.range.start=parseFloat(d[0]),j.range.end=parseFloat(d[1])),g.onload=function(){g.status<200||g.status>299||(h=!1,j.searching?(j.bytesLoaded=j.range.end,e.call(i,g.response,j).then(function(a){f.resolve(a)})):b.call(i,g.response,j.url,j.range.start).then(function(a){f.resolve(a)}))},g.onloadend=g.onerror=function(){h&&(h=!1,i.errHandler.downloadError("SIDX",j.url,g),f.reject(g))},g.open("GET",j.url),g.responseType="arraybuffer",g.setRequestHeader("Range","bytes="+j.range.start+"-"+j.range.end),g.send(null),i.debug.log("Perform SIDX load: "+j.url),f.promise};return{debug:void 0,errHandler:void 0,loadSegments:f,loadInitialization:d,parseSegments:b,parseSIDX:a,findSIDX:e}},Dash.dependencies.BaseURLExtensions.prototype={constructor:Dash.dependencies.BaseURLExtensions},Dash.dependencies.DashHandler=function(){"use strict";var a,b,c,d=-1,e=function(a,b){var c=null;return b&&b.Representation_asArray&&b.Representation_asArray.length>0&&(c=b.Representation_asArray[a]),c},f=function(a,b){var c=b.toString();return a.split("$Number$").join(c)},g=function(a,b){var c=b.toString();return a.split("$Time$").join(c)},h=function(a,b){var c=b.toString();return a.split("$Bandwidth$").join(c)},i=function(a,b){if(null===b||-1===a.indexOf("$RepresentationID$"))return a;var c=b.toString();return a.split("$RepresentationID$").join(c)},j=function(a,b){var c;return c=a===b?a:-1!==a.indexOf("http://")?a:b+a},k=function(a,b){var d=Q.defer(),f=e(a,b),g=null,k=null,l=null,m=null,n=this;return f?(n.debug.log("Getting the initialization request."),f.hasOwnProperty("SegmentTemplate")?f.SegmentTemplate.hasOwnProperty("initialization")&&(k=f.SegmentTemplate.initialization,k=h(k,f.bandwidth),k=i(k,f.id)):f.hasOwnProperty("SegmentList")&&f.SegmentList.hasOwnProperty("Initialization")&&f.SegmentList.Initialization.hasOwnProperty("range")?(k=f.SegmentList.Initialization.hasOwnProperty("sourceURL")?f.SegmentList.Initialization.sourceURL:f.BaseURL,m=f.SegmentList.Initialization.range):f.hasOwnProperty("SegmentList")&&f.SegmentList.hasOwnProperty("Initialization")&&f.SegmentList.Initialization.hasOwnProperty("sourceURL")?k=f.SegmentList.Initialization.sourceURL:f.hasOwnProperty("SegmentBase")&&f.SegmentBase.hasOwnProperty("Initialization")&&f.SegmentBase.Initialization.hasOwnProperty("range")?(k=f.BaseURL,m=f.SegmentBase.Initialization.range):f.hasOwnProperty("mimeType")&&n.manifestExt.getIsTextTrack(f.mimeType)?(k=f.BaseURL,m=0):(l=f.BaseURL,n.baseURLExt.loadInitialization(l).then(function(b){n.debug.log("Got an initialization."),g=new MediaPlayer.vo.SegmentRequest,g.streamType=c,g.type="Initialization Segment",g.url=j(l,f.BaseURL),g.range=b,g.quality=a,d.resolve(g)},function(a){d.reject(a)})),k&&k.length>0&&(n.debug.log("Got an initialization."),g=new MediaPlayer.vo.SegmentRequest,g.streamType=c,g.type="Initialization Segment",g.url=j(k,f.BaseURL),g.range=m,g.quality=a,d.resolve(g)),d.promise):Q.reject("no represenation")},l=function(c){var e,f,g,h,i,j,k=!1;return this.debug.log("Checking for stream end..."),a?(this.debug.log("Live never ends! (TODO)"),k=!1):c.hasOwnProperty("segments")&&null!==c.segments?(this.debug.log("Segments: "+d+" / "+c.segments.length),k=d>=c.segments.length):c.hasOwnProperty("SegmentTemplate")&&!c.SegmentTemplate.hasOwnProperty("SegmentTimeline")&&(f=1,i=1,h=b,c.SegmentTemplate.hasOwnProperty("duration")&&(e=c.SegmentTemplate.duration,c.SegmentTemplate.hasOwnProperty("timescale")&&(f=c.SegmentTemplate.timescale),c.SegmentTemplate.hasOwnProperty("startNumber")&&(i=c.SegmentTemplate.startNumber),g=e/f,j=d-i,this.debug.log("SegmentTemplate: "+g+" * "+j+" = "+g*j+" / "+h),k=g*j>=h)),Q.when(k)},m=function(a,c){var d,e,h,i,j,k,l,m,n=[],o=0,p=1,q=1;for(a.hasOwnProperty("startNumber")&&(p=a.startNumber),a.hasOwnProperty("timescale")&&(q=a.timescale),d=c.S_asArray,h=0,i=d.length;i>h;h+=1)for(e=d[h],k=0,e.hasOwnProperty("r")&&(k=e.r),0>k&&(k=(b-o/q)/(e.d/q)-1),j=0;k>=j;j+=1)l=new Dash.vo.Segment,l.timescale=q,0===j&&e.hasOwnProperty("t")?(l.startTime=e.t,o=e.t):l.startTime=o,l.duration=e.d,m=a.media,m=f(m,p),m=g(m,l.startTime),l.media=m,n.push(l),o+=l.duration,p+=1;return Q.when(n)},n=function(a){var b,c,d,e,f,g=[],h=1;for(a.hasOwnProperty("startNumber")&&(h=Math.max(a.startNumber,1)),f=(h-1)*a.duration,b=0,c=a.SegmentURL_asArray.length;c>b;b+=1)e=a.SegmentURL_asArray[b],d=new Dash.vo.Segment,d.media=e.media,d.mediaRange=e.mediaRange,d.index=e.index,d.indexRange=e.indexRange,d.timescale=a.timescale,d.duration=a.duration,d.startTime=f+b*a.duration,g.push(d);return Q.when(g)},o=function(a){var b=a.BaseURL,c=null;return a.hasOwnProperty("SegmentBase")&&a.SegmentBase.hasOwnProperty("indexRange")&&(c=a.SegmentBase.indexRange),this.baseURLExt.loadSegments(b,c)},p=function(a){var b;return b=a.hasOwnProperty("SegmentTemplate")&&!a.SegmentTemplate.hasOwnProperty("SegmentTimeline")?Q.when(null):a.hasOwnProperty("segments")&&null!==a.segments?Q.when(a.segments):a.hasOwnProperty("SegmentTemplate")&&a.SegmentTemplate.hasOwnProperty("SegmentTimeline")?m.call(this,a.SegmentTemplate,a.SegmentTemplate.SegmentTimeline):a.hasOwnProperty("SegmentList")?n.call(this,a.SegmentList):o.call(this,a)},q=function(a,b){var c,d,e,f,g=-1;if(b&&b.length>0)for(f=b.length-1;f>=0;f--){if(c=b[f],d=c.startTime/c.timescale,e=c.duration/c.timescale,a+Dash.dependencies.DashHandler.EPSILON>=d&&a-Dash.dependencies.DashHandler.EPSILON<=d+e){g=f;break}-1===g&&a-Dash.dependencies.DashHandler.EPSILON>d+e&&(g=f+1)}return-1===g&&(console.log("Couldn't figure out a time!"),console.log("Time: "+a),console.log(b)),Q.when(g)},r=function(a,b){var c,d,e=-1,f=1,g=1;if(!b.hasOwnProperty("duration"))throw"Expected 'duration' attribute on SegmentTemplate!";return c=b.duration,b.hasOwnProperty("timescale")&&(f=b.timescale),b.hasOwnProperty("startNumber")&&(g=b.startNumber),d=c/f,e=Math.floor(a/d),e+=g,Q.when(e)},s=function(a,b,d,e){var k,l,m=new MediaPlayer.vo.SegmentRequest,n=1,o=1;return b.hasOwnProperty("timescale")&&(n=b.timescale),b.hasOwnProperty("startNumber")&&(o=b.startNumber),l=b.duration*a/n,l=Math.floor(l),k=b.media,k=f(k,a),k=g(k,l),k=h(k,d.bandwidth),k=i(k,d.id),m.streamType=c,m.type="Media Segment",m.url=j(k,d.BaseURL),m.duration=b.duration/n,m.timescale=n,m.startTime=(a-o)*b.duration/n,m.quality=e,m.index=a,Q.when(m)},t=function(a,b,d,e){if(null===b||void 0===b)return Q.when(null);var k,l=new MediaPlayer.vo.SegmentRequest;return k=j(b.media,d.BaseURL),k=f(k,a),k=g(k,b.startTime),k=h(k,d.bandwidth),k=i(k,d.id),l.streamType=c,l.type="Media Segment",l.url=k,l.range=b.mediaRange,l.startTime=b.startTime/b.timescale,l.duration=b.duration/b.timescale,l.timescale=b.timescale,l.quality=e,l.index=a,Q.when(l)},u=function(a,b,c){var f,g,h,i=e(b,c),j=!1,k=this;return i?(k.debug.log("Getting the request for time: "+a),f=Q.defer(),p.call(k,i).then(function(b){var c;if(k.debug.log("Got segments."),k.debug.log(b),null===b){if(!i.hasOwnProperty("SegmentTemplate"))throw"Expected SegmentTemplate!";j=!0,k.debug.log("No segments found, so we must be using a SegmentTemplate."),c=r.call(k,a,i.SegmentTemplate)}else k.debug.log("Got a list of segments, so dig deeper."),i.segments=b,j=!1,c=q.call(k,a,b);return c},function(){f.reject()}).then(function(b){return k.debug.log("Index for time "+a+" is "+b),d=b,l.call(k,i)}).then(function(a){var c=null;return k.debug.log("Stream finished? "+a),a?(g=new MediaPlayer.vo.SegmentRequest,g.action=g.ACTION_COMPLETE,g.index=d,k.debug.log("Signal complete."),k.debug.log(g),f.resolve(g)):j?c=s.call(k,d,i.SegmentTemplate,i,b):(h=i.segments[d],c=t.call(k,d,h,i,b)),c}).then(function(a){k.debug.log("Got a request."),k.debug.log(a),f.resolve(a)}),f.promise):Q.reject("no represenation")},v=function(a,b){var c,f,g,h=e(a,b),i=this;if(!h)return Q.reject("no represenation");if(i.debug.log("Getting the next request."),-1===d)throw"You must call getSegmentRequestForTime first.";return d+=1,i.debug.log("New index: "+d),c=Q.defer(),l.call(i,h).then(function(b){i.debug.log("Stream finished? "+b),b?(f=new MediaPlayer.vo.SegmentRequest,f.action=f.ACTION_COMPLETE,f.index=d,i.debug.log("Signal complete."),i.debug.log(f),c.resolve(f)):p.call(i,h).then(function(b){var c;if(i.debug.log("Got segments."),i.debug.log(b),null===b){if(!h.hasOwnProperty("SegmentTemplate"))throw"Expected SegmentTemplate!";i.debug.log("No segments found, so we must be using a SegmentTemplate."),c=s.call(i,d,h.SegmentTemplate,h,a)}else h.segments=b,g=h.segments[d],c=t.call(i,d,g,h,a);return c},function(){c.reject()}).then(function(a){i.debug.log("Got a request."),i.debug.log(a),c.resolve(a)})}),c.promise},w=function(a,b,c,d){var f,g,h,i=this,j=e(a,b),k=Math.max(c-d,0),l=Q.defer(),m=0,n=1;return j?(p.call(i,j).then(function(a){if(null===a||void 0===a){if(!j.hasOwnProperty("SegmentTemplate"))throw"Expected SegmentTemplate!";j.SegmentTemplate.hasOwnProperty("timescale")&&(n=j.SegmentTemplate.timescale),h=j.SegmentTemplate.duration,f=h/n}else g=a[0],g.hasOwnProperty("timescale")&&(n=g.timescale),h=g.duration,f=h/n;m=Math.ceil(k/f),l.resolve(m)},function(){l.resolve(0)}),l.promise):Q.reject("no represenation")},x=function(b,c){var f,g,h,i,j=this,k=e(b,c),l=!1,m=1,n=1,o=Q.defer();return k?(g=d,0>g&&(l=a,g=0),p.call(j,k).then(function(a){if(null===a||void 0===a){if(!k.hasOwnProperty("SegmentTemplate"))throw"Expected SegmentTemplate!";i=k.SegmentTemplate.duration,k.SegmentTemplate.hasOwnProperty("timescale")&&(m=k.SegmentTemplate.timescale),k.SegmentTemplate.hasOwnProperty("startNumber")&&(n=k.SegmentTemplate.startNumber),f=i/m*Math.max(g-n,0)}else(l||g>=a.length)&&(g=a.length-1),h=a[g].startTime,i=a[g].duration,a[g].hasOwnProperty("timescale")&&(m=a[g].timescale),f=h/m;o.resolve(f)},function(){o.reject()}),o.promise):Q.reject("no represenation")};return{debug:void 0,baseURLExt:void 0,manifestModel:void 0,manifestExt:void 0,errHandler:void 0,getType:function(){return c},setType:function(a){c=a},getIsLive:function(){return a},setIsLive:function(b){a=b},getDuration:function(){return b},setDuration:function(a){b=a},getInitRequest:k,getSegmentRequestForTime:u,getNextSegmentRequest:v,getCurrentTime:x,getSegmentCountForDuration:w}},Dash.dependencies.DashHandler.EPSILON=.003,Dash.dependencies.DashHandler.prototype={constructor:Dash.dependencies.DashHandler},Dash.dependencies.DashManifestExtensions=function(){"use strict"},Dash.dependencies.DashManifestExtensions.prototype={constructor:Dash.dependencies.DashManifestExtensions,getIsAudio:function(a){"use strict";var b,c,d,e=a.ContentComponent_asArray,f=!1,g=!1;if(e)for(b=0,c=e.length;c>b;b+=1)"audio"===e[b].contentType&&(f=!0,g=!0);if(a.hasOwnProperty("mimeType")&&(f=-1!==a.mimeType.indexOf("audio"),g=!0),!g)for(b=0,c=a.Representation_asArray.length;!g&&c>b;)d=a.Representation_asArray[b],d.hasOwnProperty("mimeType")&&(f=-1!==d.mimeType.indexOf("audio"),g=!0),b+=1;return f&&(a.type="audio"),Q.when(f)},getIsVideo:function(a){"use strict";var b,c,d,e=a.ContentComponent_asArray,f=!1,g=!1;if(e)for(b=0,c=e.length;c>b;b+=1)"video"===e[b].contentType&&(f=!0,g=!0);if(a.hasOwnProperty("mimeType")&&(f=-1!==a.mimeType.indexOf("video"),g=!0),!g)for(b=0,c=a.Representation_asArray.length;!g&&c>b;)d=a.Representation_asArray[b],d.hasOwnProperty("mimeType")&&(f=-1!==d.mimeType.indexOf("video"),g=!0),b+=1;return f&&(a.type="video"),Q.when(f)},getIsText:function(a){"use strict";var b,c,d,e=a.ContentComponent_asArray,f=!1,g=!1;if(e)for(b=0,c=e.length;c>b;b+=1)"text"===e[b].contentType&&(f=!0,g=!0);if(a.hasOwnProperty("mimeType")&&(f=-1!==a.mimeType.indexOf("text"),g=!0),!g)for(b=0,c=a.Representation_asArray.length;!g&&c>b;)d=a.Representation_asArray[b],d.hasOwnProperty("mimeType")&&(f=-1!==d.mimeType.indexOf("text"),g=!0),b+=1;return Q.when(f)},getIsTextTrack:function(a){return"text/vtt"===a||"application/ttml+xml"===a},getIsMain:function(){"use strict";return Q.when(!1)},processAdaptation:function(a){"use strict";return void 0!==a.Representation_asArray&&null!==a.Representation_asArray&&a.Representation_asArray.sort(function(a,b){return a.bandwidth-b.bandwidth}),a},getDataForId:function(a,b,c){"use strict";var d,e,f=b.Period_asArray[c].AdaptationSet_asArray;for(d=0,e=f.length;e>d;d+=1)if(f[d].hasOwnProperty("id")&&f[d].id===a)return Q.when(f[d]);return Q.when(null)},getDataForIndex:function(a,b,c){"use strict";var d=b.Period_asArray[c].AdaptationSet_asArray;return Q.when(d[a])},getDataIndex:function(a,b,c){"use strict";var d,e,f=b.Period_asArray[c].AdaptationSet_asArray;for(d=0,e=f.length;e>d;d+=1)if(f[d]===a)return Q.when(d);return Q.when(-1)},getVideoData:function(a,b){"use strict";var c,d,e=this,f=a.Period_asArray[b].AdaptationSet_asArray,g=Q.defer(),h=[];for(c=0,d=f.length;d>c;c+=1)h.push(this.getIsVideo(f[c]));return Q.all(h).then(function(a){var b=!1;for(c=0,d=a.length;d>c;c+=1)a[c]===!0&&(b=!0,g.resolve(e.processAdaptation(f[c])));b||g.resolve(null)}),g.promise},getTextData:function(a,b){"use strict";var c,d,e=this,f=a.Period_asArray[b].AdaptationSet_asArray,g=Q.defer(),h=[];for(c=0,d=f.length;d>c;c+=1)h.push(this.getIsText(f[c]));return Q.all(h).then(function(a){var b=!1;for(c=0,d=a.length;d>c;c+=1)a[c]===!0&&(b=!0,g.resolve(e.processAdaptation(f[c])));b||g.resolve(null)}),g.promise},getAudioDatas:function(a,b){"use strict";var c,d,e=this,f=a.Period_asArray[b].AdaptationSet_asArray,g=Q.defer(),h=[];for(c=0,d=f.length;d>c;c+=1)h.push(this.getIsAudio(f[c]));return Q.all(h).then(function(a){var b=[];for(c=0,d=a.length;d>c;c+=1)a[c]===!0&&b.push(e.processAdaptation(f[c]));g.resolve(b)}),g.promise},getPrimaryAudioData:function(a,b){"use strict";var c,d,e=Q.defer(),f=[],g=this;return this.getAudioDatas(a,b).then(function(a){for(a&&0!==a.length||e.resolve(null),c=0,d=a.length;d>c;c+=1)f.push(g.getIsMain(a[c]));Q.all(f).then(function(b){var f=!1;for(c=0,d=b.length;d>c;c+=1)b[c]===!0&&(f=!0,e.resolve(g.processAdaptation(a[c])));f||e.resolve(a[0])})}),e.promise},getCodec:function(a){"use strict";var b=a.Representation_asArray[0],c=b.mimeType+';codecs="'+b.codecs+'"';return Q.when(c)},getMimeType:function(a){"use strict";return Q.when(a.Representation_asArray[0].mimeType)},getKID:function(a){"use strict";return a&&a.hasOwnProperty("cenc:default_KID")?a["cenc:default_KID"]:null},getContentProtectionData:function(a){"use strict";return a&&a.hasOwnProperty("ContentProtection_asArray")&&0!==a.ContentProtection_asArray.length?Q.when(a.ContentProtection_asArray):Q.when(null)},getSegmentInfoFor:function(a){return a.hasOwnProperty("SegmentBase")?a.SegmentBase:a.hasOwnProperty("SegmentList")?a.SegmentList:a.hasOwnProperty("SegmentTemplate")?a.SegmentTemplate:null},getLiveOffset:function(a){"use strict";var b=15;return a.hasOwnProperty("suggestedPresentationDelay")&&(b=a.suggestedPresentationDelay),Q.when(b)},getLiveStart:function(a,b){var c,d,e=0,f=1,g=1,h=null,i=null;return d=a.Period_asArray[b].AdaptationSet_asArray[1].Representation_asArray[0],d.hasOwnProperty("SegmentList")?(h=d.SegmentList,h.hasOwnProperty("startNumber")&&(f=Math.max(h.startNumber,1)),h.hasOwnProperty("timescale")&&(g=h.timescale),c=h.duration,e=(f-1)*c/g):d.hasOwnProperty("SegmentTemplate")&&(i=d.SegmentTemplate,i.hasOwnProperty("startNumber")&&(f=Math.max(i.startNumber,1)),i.hasOwnProperty("timescale")&&(g=i.timescale),c=i.duration,e=i.hasOwnProperty("SegmentTimeline")?i.SegmentTimeline.S_asArray[0].t/g:(f-1)*c/g),Q.when(e)},getLiveEdge:function(a,b){"use strict";var c,d=this,e=Q.defer(),f=0,g=new Date,h=a.availabilityStartTime;return d.getLiveOffset(a).then(function(i){a.hasOwnProperty("availabilityEndTime")?(c=a.availabilityEndTime,f=(c.getTime()-h.getTime())/1e3):f=(g.getTime()-h.getTime())/1e3,d.getLiveStart(a,b).then(function(a){f+=a,f-=i,e.resolve(f)})}),e.promise},getPresentationOffset:function(a,b){var c,d,e=this,f=Q.defer(),g=0,h=1;return e.getRepresentationFor(a,b).then(function(a){d=e.getSegmentInfoFor(a),null!==d&&void 0!==d&&d.hasOwnProperty("presentationTimeOffset")&&(c=d.presentationTimeOffset,d.hasOwnProperty("timescale")&&(h=d.timescale),g=c/h),f.resolve(g)}),f.promise},getIsLive:function(a){"use strict";var b=!1,c="dynamic";return a.hasOwnProperty("type")&&(b=a.type===c),b},getIsDVR:function(a,b){"use strict";var c,d;return c=!isNaN(a.timeShiftBufferDepth),d=b&&c,Q.when(d)},getIsOnDemand:function(a){"use strict";var b=!1;return a.profiles&&a.profiles.length>0&&(b=-1!==a.profiles.indexOf("urn:mpeg:dash:profile:isoff-on-demand:2011")),Q.when(b)},getDuration:function(a,b){"use strict";var c=0/0;return b?c=Number.POSITIVE_INFINITY:a.mediaPresentationDuration?c=a.mediaPresentationDuration:a.availabilityEndTime&&a.availabilityStartTime&&(c=a.availabilityEndTime.getTime()-a.availabilityStartTime.getTime()),Q.when(c)},getDurationForPeriod:function(a,b,c){"use strict";var d=0/0;return c?d=Number.POSITIVE_INFINITY:b.Period_asArray.length>1&&void 0!==b.Period_asArray[a].duration?d=b.Period_asArray[a].duration:b.mediaPresentationDuration?d=b.mediaPresentationDuration:b.availabilityEndTime&&b.availabilityStartTime&&(d=b.availabilityEndTime.getTime()-b.availabilityStartTime.getTime()),Q.when(d)},getBandwidth:function(a){"use strict";return Q.when(a.bandwidth)},getRefreshDelay:function(a){"use strict";var b=0/0;return a.hasOwnProperty("minimumUpdatePeriod")&&(b=parseFloat(a.minimumUpdatePeriod)),Q.when(b)},getRepresentationCount:function(a){"use strict";return Q.when(a.Representation_asArray.length)},getRepresentationFor:function(a,b){"use strict";return Q.when(b.Representation_asArray[a])},getPeriodCount:function(a){"use strict";return Q.when(a.Period_asArray.length)},getTimestampOffsetForPeriod:function(a,b,c,d){var e,f=this,g=Q.defer();return f.getPresentationOffset(c,d).then(function(c){f.getPeriodStart(b,a).then(function(a){e=a-c,g.resolve(e)})}),g.promise},getPeriodStart:function(a,b){var c,d,e=this,f=e.getIsLive(a),g=null,h=null,i=null;for(c=0;b>=c;c+=1)g=a.Period_asArray[c],g.hasOwnProperty("start")?d=g.start:null!==h&&null!==i?d=h+i:0!==c||f||(d=0),g.hasOwnProperty("duration")&&(i=g.duration),h=d;return Q.when(d)}},Dash.dependencies.DashMetricsExtensions=function(){"use strict";var a=function(a,b){var c,d,e,f,g,h,i,j;for(h=0;hf;f+=1)g=i.getInt8(j),e+=String.fromCharCode(g),j+=1;"moof"!==e&&"traf"!==e&&"tfdt"!==e&&(j+=d-8)}if(j===i.byteLength)throw"Error finding live offset.";return c=i.getUint8(j),this.debug.log("position: "+j),0===c?(j+=4,b=i.getUint32(j,!1)):(j+=d-16,b=utils.Math.to64BitNumber(i.getUint32(j+4,!1),i.getUint32(j,!1))),h.resolve({version:c,base_media_decode_time:b}),h.promise},b=function(a){for(var b,c,d,e,f,g,h,i=new DataView(a),j=0;"sidx"!==f&&je;e+=1)h=i.getInt8(j),f+=String.fromCharCode(h),j+=1;"moof"!==f&&"traf"!==f&&"sidx"!==f?j+=g-8:"sidx"===f&&(j-=8)}return b=i.getUint8(j+8),j+=12,c=i.getUint32(j+4,!1),j+=8,d=0===b?i.getUint32(j,!1):utils.Math.to64BitNumber(i.getUint32(j+4,!1),i.getUint32(j,!1)),Q.when({earliestPresentationTime:d,timescale:c})},c=function(b){var c,d,e,f=Q.defer(),g=new XMLHttpRequest,h=!1;return c=b,g.onloadend=function(){h||(d="Error loading fragment: "+c,f.reject(d))},g.onload=function(){h=!0,e=a(g.response),f.resolve(e)},g.onerror=function(){d="Error loading fragment: "+c,f.reject(d)},g.responseType="arraybuffer",g.open("GET",c),g.send(null),f.promise};return{debug:void 0,loadFragment:c,parseTFDT:a,parseSIDX:b}},Dash.dependencies.FragmentExtensions.prototype={constructor:Dash.dependencies.FragmentExtensions},Dash.vo.Segment=function(){"use strict";this.indexRange=null,this.index=null,this.mediaRange=null,this.media=null,this.duration=0/0,this.startTime=0/0,this.timescale=0/0},Dash.vo.Segment.prototype={constructor:Dash.vo.Segment},MediaPlayer.dependencies.AbrController=function(){"use strict";var a=!0,b={},c={},d=function(a){var c;return b.hasOwnProperty(a)||(b[a]=0),c=b[a]},e=function(a,c){b[a]=c},f=function(a){var b;return c.hasOwnProperty(a)||(c[a]=0),b=c[a]},g=function(a,b){c[a]=b};return{debug:void 0,abrRulesCollection:void 0,manifestExt:void 0,metricsModel:void 0,getAutoSwitchBitrate:function(){return a},setAutoSwitchBitrate:function(b){a=b},getMetricsFor:function(a){var b=Q.defer(),c=this;return c.manifestExt.getIsVideo(a).then(function(d){d?b.resolve(c.metricsModel.getMetricsFor("video")):c.manifestExt.getIsAudio(a).then(function(a){a?b.resolve(c.metricsModel.getMetricsFor("audio")):b.resolve(c.metricsModel.getMetricsFor("stream"))})}),b.promise},getPlaybackQuality:function(b,c){var h,i,j,k,l,m,n=this,o=Q.defer(),p=MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE,q=MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE,r=[];return l=d(b),m=f(b),n.debug.log("ABR enabled? ("+a+")"),a?(n.debug.log("Check ABR rules."),n.getMetricsFor(c).then(function(a){n.abrRulesCollection.getRules().then(function(d){for(h=0,i=d.length;i>h;h+=1)r.push(d[h].checkIndex(l,a,c)); Q.all(r).then(function(a){for(n.debug.log(a),k={},k[MediaPlayer.rules.SwitchRequest.prototype.STRONG]=MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE,k[MediaPlayer.rules.SwitchRequest.prototype.WEAK]=MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE,k[MediaPlayer.rules.SwitchRequest.prototype.DEFAULT]=MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE,h=0,i=a.length;i>h;h+=1)j=a[h],j.quality!==MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE&&(k[j.priority]=Math.min(k[j.priority],j.quality));k[MediaPlayer.rules.SwitchRequest.prototype.WEAK]!==MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE&&(q=MediaPlayer.rules.SwitchRequest.prototype.WEAK,p=k[MediaPlayer.rules.SwitchRequest.prototype.WEAK]),k[MediaPlayer.rules.SwitchRequest.prototype.DEFAULT]!==MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE&&(q=MediaPlayer.rules.SwitchRequest.prototype.DEFAULT,p=k[MediaPlayer.rules.SwitchRequest.prototype.DEFAULT]),k[MediaPlayer.rules.SwitchRequest.prototype.STRONG]!==MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE&&(q=MediaPlayer.rules.SwitchRequest.prototype.STRONG,p=k[MediaPlayer.rules.SwitchRequest.prototype.STRONG]),p!==MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE&&void 0!==p&&(l=p),q!==MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE&&void 0!==q&&(m=q),n.manifestExt.getRepresentationCount(c).then(function(a){0>l&&(l=0),l>=a&&(l=a-1),m!=MediaPlayer.rules.SwitchRequest.prototype.STRONG&&m!=MediaPlayer.rules.SwitchRequest.prototype.WEAK&&(m=MediaPlayer.rules.SwitchRequest.prototype.DEFAULT),e(b,l),n.debug.log("New quality of "+l),g(b,m),n.debug.log("New confidence of "+m),o.resolve({quality:l,confidence:m})})})})})):(n.debug.log("Unchanged quality of "+l),o.resolve({quality:l,confidence:m})),o.promise},setPlaybackQuality:function(a,b){var c=d(a);b!==c&&e(a,b)},getQualityFor:function(a){return d(a)}}},MediaPlayer.dependencies.AbrController.prototype={constructor:MediaPlayer.dependencies.AbrController},MediaPlayer.dependencies.BufferController=function(){"use strict";var a,b,c,d,e=.5,f=22,g="WAITING",h="READY",i="VALIDATING",j="LOADING",k=g,l=!1,m=!1,n=!1,o=!0,p=[],q=!1,r=-1,s=!0,t=-1,u=!1,v=!1,w=!1,x=!1,y=[],z=null,A=Q.defer(),B=null,C=null,D=-1,E=0,F=0,G=null,H=0,I=!1,J=null,K=0,L=!1,M=null,N=null,O=null,P=null,R=!0,S=function(a){var b=this;b.debug.log("BufferController "+c+" setState to:"+a),k=a,null!==G&&b.fragmentController.onBufferControllerStateChange()},T=function(a,b){var c=0,d=null;R===!1&&(d=P.start,c=a.getTime()-d.getTime(),P.duration=c,P.stopreason=b,R=!0)},U=function(){var a=this.manifestModel.getValue(),b=this.manifestExt.getIsLive(a);return w=!0,Q.when(b)},V=function(){if(l&&m){var a=this;U.call(this).then(function(b){v=b,a.debug.log("BufferController begin "+c+" validation"),S.call(a,h),a.requestScheduler.startScheduling(a,rb),G=a.fragmentController.attachBufferController(a)})}},W=function(){var a;this.requestScheduler.isScheduled(this)||(q===!1&&(a=new Date,T(a,MediaPlayer.vo.metrics.PlayList.Trace.USER_REQUEST_STOP_REASON),O=this.metricsModel.addPlayList(c,a,0,MediaPlayer.vo.metrics.PlayList.INITIAL_PLAY_START_REASON)),this.debug.log("BufferController "+c+" start."),m=!0,n=!0,V.call(this))},X=function(a){var b;this.debug.log("BufferController "+c+" seek: "+a),q=!0,r=a,b=new Date,T(b,MediaPlayer.vo.metrics.PlayList.Trace.USER_REQUEST_STOP_REASON),O=this.metricsModel.addPlayList(c,b,r,MediaPlayer.vo.metrics.PlayList.SEEK_START_REASON),W.call(this)},Y=function(){k!==g&&(this.debug.log("BufferController "+c+" stop."),S.call(this,g),this.requestScheduler.stopScheduling(this),this.fragmentController.cancelPendingRequestsForModel(G),m=!1,n=!1,T(new Date,MediaPlayer.vo.metrics.PlayList.Trace.USER_REQUEST_STOP_REASON))},Z=function(a,b){var c=null;return b&&b.Representation_asArray&&b.Representation_asArray.length>0&&(c=b.Representation_asArray[a]),c},$=function(){var a=this;k===j&&(u&&(u=!1,this.videoModel.stallStream(c,u)),S.call(a,h))},_=function(a){if(this.fragmentController.isInitializationRequest(a))S.call(this,h);else{S.call(this,j);var b=this,c=b.fragmentController.getLoadingTime(b);setTimeout(function(){(M||N)&&(S.call(b,h),qb.call(b))},c)}},ab=function(a,b){this.fragmentController.isInitializationRequest(a)?hb.call(this,a,b):bb.call(this,a,b)},bb=function(a,b){var d=this;d.debug.log(c+" Bytes finished loading: "+a.url),K||isNaN(a.duration)||(K=a.duration),d.fragmentController.process(b.data).then(function(b){null!==b&&null!==z?Q.when(z.promise).then(function(){cb.call(d,b,a.quality).then(function(){A.promise.then(function(b){b.index-1!==a.index||x||(x=!0,u&&(u=!1,d.videoModel.stallStream(c,u)),S.call(d,h),d.system.notify("bufferingCompleted"))})})}):d.debug.log("No "+c+" bytes to push.")})},cb=function(a,b){var d=this,e=a==J,h=e?B:Q.defer(),i=e?y.length:y.push(h),j=Z(t,d.getData()),l=d.videoModel.getCurrentTime(),m=new Date;return d.debug.log("Push ("+c+") bytes: "+a.byteLength),R===!0&&k!==g&&-1!==t&&(R=!1,P=d.metricsModel.appendPlayListTrace(O,j.id,null,m,l,null,1,null)),Q.when(e||2>i||y[i-2].promise).then(function(){N&&fb.call(d).then(function(){return b!==t?(h.resolve(),e&&(B=null,J=null),void 0):(Q.when(C?C.promise:!0).then(function(){d.sourceBufferExt.append(N,a,d.videoModel).then(function(){e&&(B=null,J=null),d.requestScheduler.isScheduled(d)||W.call(d),I=!1,db.call(d).then(function(){h.resolve()}),N&&d.sourceBufferExt.getAllRanges(N).then(function(a){if(a&&(d.debug.log("Append "+c+" complete: "+a.length),a.length>0)){var b,e;for(d.debug.log("Number of buffered "+c+" ranges: "+a.length),b=0,e=a.length;e>b;b+=1)d.debug.log("Buffered "+c+" Range: "+a.start(b)+" - "+a.end(b))}})},function(b){b.err.code===f&&(J=a,B=h,I=!0,F=0,Y.call(d))})}),void 0)})}),h.promise},db=function(){if(!M&&!N)return Q.when(!1);var a=this,b=Q.defer(),d=ob.call(a);return a.sourceBufferExt.getBufferLength(N,d).then(function(d){H=d,a.metricsModel.addBufferLevel(c,new Date,H),eb.call(a),b.resolve()}),b.promise},eb=function(){var a=this.bufferExt.getLeastBufferLevel(),b=2*K,c=H-a;c>b&&!C?(F=0,C=Q.defer()):b>c&&C&&(C.resolve(),C=null)},fb=function(){var a,b=this,c=Q.defer(),d=0;return I?(a=function(){gb.call(b).then(function(b){d+=b,d>=K?c.resolve():setTimeout(a,1e3*K)})},a.call(b),c.promise):Q.when(!0)},gb=function(){var a,c,d=this,e=Q.defer(),f=d.videoModel.getCurrentTime(),g=0;return c=d.fragmentController.getExecutedRequestForTime(G,f),a=c&&!isNaN(c.startTime)?c.startTime:Math.floor(f),K=c&&!isNaN(c.duration)?c.duration:1,d.sourceBufferExt.getBufferRange(N,f).then(function(c){null===c&&r===f&&N.buffered.length>0&&(a=N.buffered.end(N.buffered.length-1)),g=N.buffered.start(0),d.sourceBufferExt.remove(N,g,a,E,b).then(function(){d.fragmentController.removeExecutedRequestsBeforeTime(G,a),e.resolve(a-g)})}),e.promise},hb=function(a,b){var d=this,e=b.data,f=a.quality;d.debug.log(c+" Initialization finished loading: "+a.url),d.fragmentController.process(e).then(function(b){null!==b?(p[f]=b,f===t&&cb.call(d,b,a.quality).then(function(){z.resolve()})):d.debug.log("No "+c+" bytes to push.")})},ib=function(){var a=this,b=a.manifestModel.getValue(),c=a.manifestExt.getIsLive(b);k===j&&S.call(a,h),c||a.system.notify("segmentLoadingFailed")},jb=function(a){this.debug.log(c+" Stream is complete."),T(new Date,MediaPlayer.vo.metrics.PlayList.Trace.END_OF_CONTENT_STOP_REASON),Y.call(this),A.resolve(a)},kb=function(a,b){var d,e=null,f=this.bufferExt.getTopQualityIndex(c),g=[];if(o&&(this.debug.log("Marking a special seek for initial "+c+" playback."),q||(q=!0,r=0),o=!1),s){for(z=Q.defer(),p=[],d=0;f>=d;d+=1)g.push(this.indexHandler.getInitRequest(d,M));t=b,e=Q.all(g)}else e=Q.when(null),a&&(z=Q.defer(),t=b,p[b]&&cb.call(this,p[b],b).then(function(){z.resolve()}));return e},lb=function(b){var d,e=this;if(s&&!q)e.debug.log("Data changed - loading the "+c+" fragment for time: "+a),d=e.indexHandler.getSegmentRequestForTime(a,b,M);else{var f=Q.defer(),g=e.videoModel.getCurrentTime();d=f.promise,e.sourceBufferExt.getBufferRange(N,g).then(function(a){q=!1,null!==a&&(g=a.end),e.debug.log("Loading the "+c+" fragment for time: "+g),e.indexHandler.getSegmentRequestForTime(g,b,M).then(function(a){f.resolve(a)},function(){f.reject()})},function(){f.reject()})}return s=!1,d},mb=function(a){var b=this;null!==a?b.fragmentController.isFragmentLoadedOrPending(b,a)?"complete"!==a.action?b.indexHandler.getNextSegmentRequest(t,M).then(mb.bind(b)):(Y.call(b),S.call(b,h)):(b.debug.log("Loading an "+c+" fragment: "+a.url),Q.when(C?C.promise:!0).then(function(){b.fragmentController.prepareFragmentForLoading(b,a,_,ab,ib,jb).then(function(){S.call(b,h)})})):S.call(b,h)},nb=function(){n&&(d>H&&d0?(F--,lb.call(a,t).then(mb.bind(a))):(k===i&&S.call(a,h),$.call(a))},rb=function(){var a,b=this,d=!1,f=null,g=new Date,l=b.videoModel.getCurrentTime(),m=ob.call(b);if(b.debug.log("BufferController.validate() "+c+" | state: "+k),b.debug.log(c+" Playback rate: "+b.videoModel.getElement().playbackRate),b.debug.log(c+" Working time: "+m),b.debug.log(c+" Video time: "+l),b.debug.log("Current "+c+" buffer length: "+H),nb.call(b),k===j&&e>H)u||(b.debug.log("Stalling "+c+" Buffer: "+c),T(new Date,MediaPlayer.vo.metrics.PlayList.Trace.REBUFFERING_REASON),u=!0,n=!0,b.videoModel.stallStream(c,u));else if(k===h){S.call(b,i);var o=b.manifestModel.getValue().minBufferTime;b.bufferExt.decideBufferLength(o,E,n).then(function(a){b.debug.log("Buffer time: "+a),b.setMinBufferTime(a),b.requestScheduler.adjustExecuteInterval()}),b.abrController.getPlaybackQuality(c,M).then(function(e){var h=e.quality;if(b.debug.log(c+" Playback quality: "+h),b.debug.log("Populate "+c+" buffers."),void 0!==h&&(a=h),d=h!==t,d===!0){if(b.fragmentController.abortRequestsForModel(G),f=Z(a,b.getData()),null===f||void 0===f)throw"Unexpected error!";b.manifestExt.getTimestampOffsetForPeriod(D,b.manifestModel.getValue(),h,M).then(function(a){N.timestampOffset!==a&&(N.timestampOffset=a)}),T(new Date,MediaPlayer.vo.metrics.PlayList.Trace.REPRESENTATION_SWITCH_STOP_REASON),b.metricsModel.addRepresentationSwitch(c,g,l,f.id)}return b.debug.log(d?c+" Quality changed to: "+h:"Quality didn't change."),pb.call(b,h)}).then(function(e){F=e,kb.call(b,d,a).then(function(a){if(null!==a){var d,e,f=a.length;for(e=0;f>e;e+=1)d=a[e],b.debug.log("Loading "+c+" initialization: "+d.url),b.debug.log(d),b.fragmentController.prepareFragmentForLoading(b,d,_,ab,ib,jb).then(function(){S.call(b,h)})}}),qb.call(b)})}else k===i&&S.call(b,h)};return{videoModel:void 0,metricsModel:void 0,manifestExt:void 0,manifestModel:void 0,bufferExt:void 0,sourceBufferExt:void 0,abrController:void 0,fragmentExt:void 0,indexHandler:void 0,debug:void 0,system:void 0,errHandler:void 0,initialize:function(a,b,c,d,e,f,g,h){var i=this,j=i.manifestModel.getValue(),k=i.manifestExt.getIsLive(j);i.setMediaSource(h),i.setVideoModel(e),i.setType(a),i.setPeriodIndex(b),i.setData(c).then(function(){l=!0,V.call(i)}),i.setBuffer(d),i.setScheduler(f),i.setFragmentController(g),i.indexHandler.setIsLive(k),i.manifestExt.getDurationForPeriod(b,i.manifestModel.getValue()).then(function(a){E=a,i.indexHandler.setDuration(a),i.bufferExt.decideBufferLength(j.minBufferTime,E,n).then(function(a){i.setMinBufferTime(a)})})},getType:function(){return c},setType:function(a){c=a,void 0!==this.indexHandler&&this.indexHandler.setType(a)},getPeriodIndex:function(){return D},setPeriodIndex:function(a){D=a},getVideoModel:function(){return this.videoModel},setVideoModel:function(a){this.videoModel=a},getScheduler:function(){return this.requestScheduler},setScheduler:function(a){this.requestScheduler=a},getFragmentController:function(){return this.fragmentController},setFragmentController:function(a){this.fragmentController=a},getAutoSwitchBitrate:function(){var a=this;return a.abrController.getAutoSwitchBitrate()},setAutoSwitchBitrate:function(a){var b=this;b.abrController.setAutoSwitchBitrate(a)},getData:function(){return M},setData:function(b){var d=this,e=Q.defer(),f=M;return f||(f=b),d.abrController.getPlaybackQuality(c,f).then(function(g){d.indexHandler.getCurrentTime(g.quality,f).then(function(f){s=!0,a=f,M=b,d.seek(f),d.bufferExt.updateData(M,c),e.resolve()})}),e.promise},getBuffer:function(){return N},setBuffer:function(a){N=a},getMinBufferTime:function(){return d},setMinBufferTime:function(a){d=a},setMediaSource:function(a){b=a},isReady:function(){return k===h},isBufferingCompleted:function(){return x},clearMetrics:function(){var a=this;null!==c&&""!==c&&a.metricsModel.clearCurrentMetricsForType(c)},updateBufferState:function(){var a=this;I&&J&&!L?(L=!0,cb.call(a,J,t).then(function(){L=!1})):db.call(a)},reset:function(a){var c=this;Y.call(c),c.clearMetrics(),c.fragmentController.abortRequestsForModel(G),c.fragmentController.detachBufferController(G),G=null,y=[],z=null,p=[],A=Q.defer(),a||(c.sourceBufferExt.abort(b,N),c.sourceBufferExt.removeSourceBuffer(b,N)),M=null,N=null},start:W,seek:X,stop:Y}},MediaPlayer.dependencies.BufferController.prototype={constructor:MediaPlayer.dependencies.BufferController},MediaPlayer.dependencies.BufferExtensions=function(){"use strict";var a,b,c=0,d=0,e=null,f=null,g=function(a){var b=this.metricsExt.getCurrentHttpRequest(a);return null!==b?(b.tresponse.getTime()-b.trequest.getTime())/1e3:0},h=function(){var a,b=this,g=Q.defer();return Q.when(e?b.abrController.getPlaybackQuality("audio",e):c).then(function(e){Q.when(f?b.abrController.getPlaybackQuality("video",f):d).then(function(b){a=e.quality===c&&b.quality===d,a=a||e.confidence===MediaPlayer.rules.SwitchRequest.prototype.STRONG&&b.confidence===MediaPlayer.rules.SwitchRequest.prototype.STRONG,g.resolve(a)})}),g.promise};return{system:void 0,videoModel:void 0,manifestExt:void 0,metricsExt:void 0,metricsModel:void 0,abrController:void 0,bufferMax:void 0,updateData:function(a,b){var g=a.Representation_asArray.length-1;"audio"===b?(c=g,e=a):"video"===b&&(d=g,f=a)},getTopQualityIndex:function(a){var b=null;return"audio"===a?b=c:"video"===a&&(b=d),b},decideBufferLength:function(b,c){return a=MediaPlayer.dependencies.BufferExtensions.DEFAULT_MIN_BUFFER_TIMEb?Math.max(MediaPlayer.dependencies.BufferExtensions.DEFAULT_MIN_BUFFER_TIME,b):b>=c?Math.min(c,MediaPlayer.dependencies.BufferExtensions.DEFAULT_MIN_BUFFER_TIME):Math.min(c,b),Q.when(a)},getLeastBufferLevel:function(){var a=this.metricsModel.getReadOnlyMetricsFor("video"),b=this.metricsExt.getCurrentBufferLevel(a),c=this.metricsModel.getReadOnlyMetricsFor("audio"),d=this.metricsExt.getCurrentBufferLevel(c),e=null;return e=null===b||null===d?null!==d?d.level:null!==b?b.level:null:Math.min(d.level,b.level)},getRequiredBufferLength:function(c,d,e,f){var i,j=this,k=j.metricsModel.getReadOnlyMetricsFor("video"),l=j.metricsModel.getReadOnlyMetricsFor("audio"),m=f>=MediaPlayer.dependencies.BufferExtensions.LONG_FORM_CONTENT_DURATION_THRESHOLD,n=Q.defer(),o=null;return j.bufferMax===MediaPlayer.dependencies.BufferExtensions.BUFFER_SIZE_MIN?(i=a,n.resolve(i)):j.bufferMax===MediaPlayer.dependencies.BufferExtensions.BUFFER_SIZE_INFINITY?(i=f,n.resolve(i)):j.bufferMax===MediaPlayer.dependencies.BufferExtensions.BUFFER_SIZE_REQUIRED?(b=a,e||c||(o=h.call(j)),Q.when(o).then(function(a){a&&(b=m?MediaPlayer.dependencies.BufferExtensions.BUFFER_TIME_AT_TOP_QUALITY_LONG_FORM:MediaPlayer.dependencies.BufferExtensions.BUFFER_TIME_AT_TOP_QUALITY),i=b+d+Math.max(g.call(j,k),g.call(j,l)),n.resolve(i)})):n.reject("invalid bufferMax value: "+j.bufferMax),n.promise},getBufferTarget:function(){return void 0===b?a:b}}},MediaPlayer.dependencies.BufferExtensions.BUFFER_SIZE_REQUIRED="required",MediaPlayer.dependencies.BufferExtensions.BUFFER_SIZE_MIN="min",MediaPlayer.dependencies.BufferExtensions.BUFFER_SIZE_INFINITY="infinity",MediaPlayer.dependencies.BufferExtensions.BUFFER_TIME_AT_STARTUP=1,MediaPlayer.dependencies.BufferExtensions.DEFAULT_MIN_BUFFER_TIME=8,MediaPlayer.dependencies.BufferExtensions.BUFFER_TIME_AT_TOP_QUALITY=30,MediaPlayer.dependencies.BufferExtensions.BUFFER_TIME_AT_TOP_QUALITY_LONG_FORM=300,MediaPlayer.dependencies.BufferExtensions.LONG_FORM_CONTENT_DURATION_THRESHOLD=600,MediaPlayer.dependencies.BufferExtensions.prototype.constructor=MediaPlayer.dependencies.BufferExtensions,MediaPlayer.utils.Capabilities=function(){"use strict"},MediaPlayer.utils.Capabilities.prototype={constructor:MediaPlayer.utils.Capabilities,supportsMediaSource:function(){"use strict";var a="WebKitMediaSource"in window,b="MediaSource"in window;return a||b},supportsMediaKeys:function(){"use strict";var a="WebKitMediaKeys"in window,b="MSMediaKeys"in window,c="MediaKeys"in window;return a||b||c},supportsCodec:function(a,b){"use strict";if(!(a instanceof HTMLVideoElement))throw"element must be of type HTMLVideoElement.";var c=a.canPlayType(b);return"probably"===c}},MediaPlayer.utils.Debug=function(){"use strict";var a=!0;return{eventBus:void 0,setLogToBrowserConsole:function(b){a=b},getLogToBrowserConsole:function(){return a},log:function(b){a&&console.log(b),this.eventBus.dispatchEvent({type:"log",message:b})}}},MediaPlayer.dependencies.ErrorHandler=function(){"use strict";return{eventBus:void 0,capabilityError:function(a){this.eventBus.dispatchEvent({type:"error",error:"capability",event:a})},downloadError:function(a,b,c){this.eventBus.dispatchEvent({type:"error",error:"download",event:{id:a,url:b,request:c}})},manifestError:function(a,b,c){this.eventBus.dispatchEvent({type:"error",error:"manifestError",event:{message:a,id:b,manifest:c}})},mediaSourceError:function(a){this.eventBus.dispatchEvent({type:"error",error:"mediasource",event:a})},mediaKeySessionError:function(a){this.eventBus.dispatchEvent({type:"error",error:"key_session",event:a})},mediaKeyMessageError:function(a){this.eventBus.dispatchEvent({type:"error",error:"key_message",event:a})},mediaKeySystemSelectionError:function(a){this.eventBus.dispatchEvent({type:"error",error:"key_system_selection",event:a})}}},MediaPlayer.dependencies.ErrorHandler.prototype={constructor:MediaPlayer.dependencies.ErrorHandler},MediaPlayer.utils.EventBus=function(){"use strict";var a,b=function(b,c){var d=(c?"1":"0")+b;return d in a||(a[d]=[]),a[d]},c=function(){a={}};return c(),{addEventListener:function(a,c,d){var e=b(a,d),f=e.indexOf(c);-1===f&&e.push(c)},removeEventListener:function(a,c,d){var e=b(a,d),f=e.indexOf(c);-1!==f&&e.splice(f,1)},dispatchEvent:function(a){for(var c=b(a.type,!1).slice(),d=0;dd;d++)if(a[d].getContext()==b)return a[d];return null},c=function(){for(var b=!0,c=a.length,d=0;c>d;d++)if(!a[d].isReady()){b=!1;break}return b},d=function(){for(var b=0;b0&&(b=new Uint8Array(a)),Q.when(b)},attachBufferController:function(c){if(!c)return null;var d=b(c);return d||(d=this.system.getObject("fragmentModel"),d.setContext(c),a.push(d)),d},detachBufferController:function(b){var c=a.indexOf(b);c>-1&&a.splice(c,1)},onBufferControllerStateChange:function(){c()&&d.call(this)},isFragmentLoadedOrPending:function(a,c){var d,e=b(a);return e?d=e.isFragmentLoadedOrPending(c):!1},getPendingRequests:function(a){var c=b(a);return c?c.getPendingRequests():null},getLoadingRequests:function(a){var c=b(a);return c?c.getLoadingRequests():null},isInitializationRequest:function(a){return a&&a.type&&"initialization segment"===a.type.toLowerCase()},getLoadingTime:function(a){var c=b(a);return c?c.getLoadingTime():null},getExecutedRequestForTime:function(a,b){return a?a.getExecutedRequestForTime(b):null},removeExecutedRequest:function(a,b){a&&a.removeExecutedRequest(b)},removeExecutedRequestsBeforeTime:function(a,b){a&&a.removeExecutedRequestsBeforeTime(b)},cancelPendingRequestsForModel:function(a){a&&a.cancelPendingRequests()},abortRequestsForModel:function(a){a&&a.abortRequests()},prepareFragmentForLoading:function(a,c,d,e,f,g){var h=b(a);return h&&c&&!this.isFragmentLoadedOrPending(a,c)?(h.addRequest(c),h.setCallbacks(d,e,f,g),Q.when(!0)):Q.when(null)}}},MediaPlayer.dependencies.FragmentController.prototype={constructor:MediaPlayer.dependencies.FragmentController},MediaPlayer.dependencies.FragmentLoader=function(){"use strict";var a=3,b=500,c=[],d=function(a,e){var f=new XMLHttpRequest,g=null,h=!0,i=!0,j=this;c.push(f),a.requestStartDate=new Date,a.firstByteDate=a.requestStartDate,f.open("GET",a.url,!0),f.responseType="arraybuffer",a.range&&f.setRequestHeader("Range","bytes="+a.range),f.onprogress=function(b){h&&(h=!1,(!b.lengthComputable||b.lengthComputable&&b.total!=b.loaded)&&(a.firstByteDate=new Date))},f.onload=function(){if(!(f.status<200||f.status>299)){i=!1,a.requestEndDate=new Date;var b=a.requestEndDate,c=f.response,d=a.firstByteDate.getTime()-a.requestStartDate.getTime(),e=a.requestEndDate.getTime()-a.firstByteDate.getTime(),h=a.requestEndDate.getTime()-a.requestStartDate.getTime();j.debug.log("segment loaded: ("+f.status+", "+d+"ms, "+e+"ms, "+h+"ms) "+a.url),g=j.metricsModel.addHttpRequest(a.streamType,null,a.type,a.url,null,a.range,a.requestStartDate,a.firstByteDate,a.requestEndDate,f.status,null,a.duration),j.metricsModel.appendHttpTrace(g,b,(new Date).getTime()-b.getTime(),[c.byteLength]),a.deferred.resolve({data:c,request:a})}},f.onloadend=f.onerror=function(){if(-1!==c.indexOf(f)&&(c.splice(c.indexOf(f),1),i)){i=!1,a.requestEndDate=new Date;var h=a.firstByteDate.getTime()-a.requestStartDate.getTime(),k=a.requestEndDate.getTime()-a.firstByteDate.getTime(),l=a.requestEndDate.getTime()-a.requestStartDate.getTime();j.debug.log("segment loaded: ("+f.status+", "+h+"ms, "+k+"ms, "+l+"ms) "+a.url),g=j.metricsModel.addHttpRequest(a.streamType,null,a.type,a.url,null,a.range,a.requestStartDate,a.firstByteDate,a.requestEndDate,f.status,null,a.duration),e>0?(j.debug.log("Failed loading segment: "+a.url+", retry in "+b+"ms"+" attempts: "+e),e--,setTimeout(function(){d.call(j,a,e)},b)):(j.debug.log("Failed loading segment: "+a.url+" no retry attempts left"),j.errHandler.downloadError("content",a.url,f),a.deferred.reject(f))}},f.send()};return{metricsModel:void 0,errHandler:void 0,debug:void 0,load:function(b){return b?(b.deferred=Q.defer(),d.call(this,b,a),b.deferred.promise):Q.when(null)},abort:function(){var a,b,d=c.length;for(a=0;d>a;a+=1)b=c[a],c[a]=null,b.abort(),b=null;c=[]}}},MediaPlayer.dependencies.FragmentLoader.prototype={constructor:MediaPlayer.dependencies.FragmentLoader},MediaPlayer.dependencies.FragmentModel=function(){"use strict";var a,b,c,d,e,f=[],g=[],h=[],i=5,j=function(e){var g,i=this;b.call(a,e),g=function(b,d){h.splice(h.indexOf(b),1),f.push(b),c.call(a,b,d),b.deferred=null},i.fragmentLoader.load(e).then(g.bind(a,e),d.bind(a,e))},k=function(a,b){var c=function(a,c){return a[b]c[b]?1:0};a.sort(c)},l=function(a,b){var c,d,e=a.length-1;for(d=e;d>=0;d-=1)if(c=a[d],c.url===b.url&&c.startTime===b.startTime)return!0;return!1},m=function(a){var b=f.indexOf(a);-1!==b&&f.splice(b,1)};return{system:void 0,debug:void 0,fragmentLoader:void 0,setContext:function(b){a=b},getContext:function(){return a},addRequest:function(a){a&&(g.push(a),k.call(this,g,"index"))},setCallbacks:function(a,f,g,h){b=a,e=h,d=g,c=f},isFragmentLoadedOrPending:function(a){for(var b,c=this,d=!1,e=f.length-1,i=e;i>=0;i-=1)if(b=f[i],a.startTime===b.startTime||"complete"===b.action&&a.action===b.action){if(c.debug.log(a.streamType+" Fragment already loaded for time: "+a.startTime),a.url===b.url){c.debug.log(a.streamType+" Fragment url already loaded: "+a.url),d=!0;break}m(a)}return d||(d=l.call(c,g,a)||l.call(c,h,a)),d},isReady:function(){return a.isReady()},getPendingRequests:function(){return g},getLoadingRequests:function(){return h},getLoadingTime:function(){var a,b,c=0;for(b=f.length-1;b>=0;b-=1)if(a=f[b],a.requestEndDate instanceof Date&&a.firstByteDate instanceof Date){c=a.requestEndDate.getTime()-a.firstByteDate.getTime();break}return c},getExecutedRequestForTime:function(a){var b,c=f.length-1,d=0/0,e=0/0,g=null;for(b=c;b>=0;b-=1)if(g=f[b],d=g.startTime,e=d+g.duration,!isNaN(d)&&!isNaN(e)&&a>d&&e>a)return g;return null},removeExecutedRequest:function(a){m.call(this,a)},removeExecutedRequestsBeforeTime:function(a){var b,c=f.length-1,d=0/0,e=null;for(b=c;b>=0;b-=1)e=f[b],d=e.startTime,!isNaN(d)&&a>d&&m.call(this,e)},cancelPendingRequests:function(){g=[]},abortRequests:function(){this.fragmentLoader.abort(),h=[]},executeCurrentRequest:function(){var b,c=this;if(0!==g.length&&!(h.length>=i))switch(b=g.shift(),b.action){case"complete":f.push(b),e.call(a,b);break;case"download":h.push(b),j.call(c,b);break;default:this.debug.log("Unknown request action.")}}}},MediaPlayer.dependencies.FragmentModel.prototype={constructor:MediaPlayer.dependencies.FragmentModel},MediaPlayer.dependencies.ManifestLoader=function(){"use strict";var a=3,b=500,c=null,d=function(a){var b=null;return-1!==a.indexOf("/")&&(b=a.substring(0,a.lastIndexOf("/")+1)),b},e=function(a,f){var g=d(a),h=new XMLHttpRequest,i=new Date,j=!0,k=this;this.debug.log("Start loading manifest: "+a),h.open("GET",a,!0),h.onload=function(){h.status<200||h.status>299||(j=!1,k.metricsModel.addHttpRequest("stream",null,"MPD",a,null,null,i,new Date,h.status,null,null),k.parser.parse(h.responseText,g).then(function(b){b.mpdUrl=a,c.resolve(b)},function(){c.reject(h)}))},h.onloadend=h.onerror=function(){j&&(j=!1,k.metricsModel.addHttpRequest("stream",null,"MPD",a,null,null,i,new Date,h.status,null,null),f>0?(k.debug.log("Failed loading manifest: "+a+", retry in "+b+"ms"+" attempts: "+f),f--,setTimeout(function(){e.call(k,a,f)},b)):(k.debug.log("Failed loading manifest: "+a+" no retry attempts left"),k.errHandler.downloadError("manifest",a,h),c.reject(h)))},h.send()};return{debug:void 0,parser:void 0,errHandler:void 0,metricsModel:void 0,load:function(b){return c=Q.defer(),e.call(this,b,a),c.promise}}},MediaPlayer.dependencies.ManifestLoader.prototype={constructor:MediaPlayer.dependencies.ManifestLoader},MediaPlayer.models.ManifestModel=function(){"use strict";var a;return{getValue:function(){return a},setValue:function(b){a=b}}},MediaPlayer.models.ManifestModel.prototype={constructor:MediaPlayer.models.ManifestModel},MediaPlayer.dependencies.ManifestUpdater=function(){"use strict";var a=0/0,b=null,c=null,d=function(){null!==b&&(clearInterval(b),b=null)},e=function(){d.call(this),isNaN(a)||(this.debug.log("Refresh manifest in "+a+" seconds."),b=setInterval(c.bind(this),1e3*a,this))},f=function(){var b=this,c=b.manifestModel.getValue();void 0!==c&&null!==c&&b.manifestExt.getRefreshDelay(c).then(function(c){a=c,e.call(b)})};return c=function(){var a=this,b=a.manifestModel.getValue(),c=b.mpdUrl;b.hasOwnProperty("Location")&&(c=b.Location),a.debug.log("Refresh manifest @ "+c),a.manifestLoader.load(c).then(function(b){a.manifestModel.setValue(b),a.debug.log("Manifest has been refreshed."),a.debug.log(b),f.call(a),a.system.notify("manifestUpdated")})},{debug:void 0,system:void 0,manifestModel:void 0,manifestExt:void 0,manifestLoader:void 0,setup:function(){f.call(this)},init:function(){f.call(this)},stop:function(){d.call(this)}}},MediaPlayer.dependencies.ManifestUpdater.prototype={constructor:MediaPlayer.dependencies.ManifestUpdater},MediaPlayer.dependencies.MediaSourceExtensions=function(){"use strict"},MediaPlayer.dependencies.MediaSourceExtensions.prototype={constructor:MediaPlayer.dependencies.MediaSourceExtensions,createMediaSource:function(){"use strict";var a="WebKitMediaSource"in window,b="MediaSource"in window;return b?Q.when(new MediaSource):a?Q.when(new WebKitMediaSource):null},attachMediaSource:function(a,b){"use strict";return b.setSource(window.URL.createObjectURL(a)),Q.when(!0)},detachMediaSource:function(a){"use strict";return a.setSource(""),Q.when(!0)},setDuration:function(a,b){"use strict";return a.duration=b,Q.when(a.duration)},signalEndOfStream:function(a){"use strict";return a.endOfStream(),Q.when(!0)}},MediaPlayer.models.MetricsModel=function(){"use strict";return{system:void 0,streamMetrics:{},clearCurrentMetricsForType:function(a){delete this.streamMetrics[a]},clearAllCurrentMetrics:function(){this.streamMetrics={}},getReadOnlyMetricsFor:function(a){return this.streamMetrics.hasOwnProperty(a)?this.streamMetrics[a]:null},getMetricsFor:function(a){var b;return this.streamMetrics.hasOwnProperty(a)?b=this.streamMetrics[a]:(b=this.system.getObject("metrics"),this.streamMetrics[a]=b),b},addTcpConnection:function(a,b,c,d,e,f){var g=new MediaPlayer.vo.metrics.TCPConnection;return g.tcpid=b,g.dest=c,g.topen=d,g.tclose=e,g.tconnect=f,this.getMetricsFor(a).TcpList.push(g),g},addHttpRequest:function(a,b,c,d,e,f,g,h,i,j,k,l){var m=new MediaPlayer.vo.metrics.HTTPRequest;return m.tcpid=b,m.type=c,m.url=d,m.actualurl=e,m.range=f,m.trequest=g,m.tresponse=h,m.tfinish=i,m.responsecode=j,m.interval=k,m.mediaduration=l,this.getMetricsFor(a).HttpList.push(m),m},appendHttpTrace:function(a,b,c,d){var e=new MediaPlayer.vo.metrics.HTTPRequest.Trace;return e.s=b,e.d=c,e.b=d,a.trace.push(e),e},addRepresentationSwitch:function(a,b,c,d,e){var f=new MediaPlayer.vo.metrics.RepresentationSwitch;return f.t=b,f.mt=c,f.to=d,f.lto=e,this.getMetricsFor(a).RepSwitchList.push(f),f},addBufferLevel:function(a,b,c){var d=new MediaPlayer.vo.metrics.BufferLevel;return d.t=b,d.level=c,this.getMetricsFor(a).BufferLevel.push(d),d},addPlayList:function(a,b,c,d){var e=new MediaPlayer.vo.metrics.PlayList;return e.start=b,e.mstart=c,e.starttype=d,this.getMetricsFor(a).PlayList.push(e),e},appendPlayListTrace:function(a,b,c,d,e,f,g,h){var i=new MediaPlayer.vo.metrics.PlayList.Trace;return i.representationid=b,i.subreplevel=c,i.start=d,i.mstart=e,i.duration=f,i.playbackspeed=g,i.stopreason=h,a.trace.push(i),i}}},MediaPlayer.models.MetricsModel.prototype={constructor:MediaPlayer.models.MetricsModel},MediaPlayer.dependencies.ProtectionController=function(){"use strict";var a=null,b=null,c=function(a){var b=this;b.protectionModel.removeKeySystem(a)},d=function(a,c){for(var d=this,e=0;ee;e+=1)if(g=f.start(e),h=f.end(e),null===i){if(k=Math.abs(g-b),b>=g&&h>b){i=g,j=h;continue}if(l>=k){i=g,j=h;continue}}else{if(k=g-j,!(l>=k))break;j=h}if(null!==i)return Q.when({start:i,end:j})}return Q.when(null)},getAllRanges:function(a){var b=null;try{return b=a.buffered,Q.when(b)}catch(c){return Q.when(null)}},getBufferLength:function(a,b,c){"use strict";var d=this,e=Q.defer();return d.getBufferRange(a,b,c).then(function(a){null===a?e.resolve(0):e.resolve(a.end-b)}),e.promise},waitForUpdateEnd:function(a){"use strict";var b,c=Q.defer(),d=50,e=function(){a.updating||(clearInterval(b),c.resolve(!0))},f=function(){a.removeEventListener("updateend",f,!1),c.resolve(!0)};if(a.hasOwnProperty("addEventListener"))try{a.addEventListener("updateend",f,!1)}catch(g){b=setInterval(e,d)}else b=setInterval(e,d);return c.promise},append:function(a,b){var c=Q.defer();try{"append"in a?a.append(b):"appendBuffer"in a&&a.appendBuffer(b),this.waitForUpdateEnd(a).then(function(){c.resolve()})}catch(d){c.reject({err:d,data:b})}return c.promise},remove:function(a,b,c,d,e){var f=Q.defer();try{b>=0&&d>b&&c>b&&"ended"!==e.readyState&&a.remove(b,c),this.waitForUpdateEnd(a).then(function(){f.resolve()})}catch(g){f.reject(g)}return f.promise},abort:function(a,b){"use strict";var c=Q.defer();try{"open"===a.readyState&&b.abort(),c.resolve()}catch(d){c.reject(d.description)}return c.promise}},MediaPlayer.dependencies.Stream=function(){"use strict";var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q=null,r=null,s=null,t=null,u=-1,v=null,w=-1,x=null,y=-1,z=!0,A=!1,B=!1,C=null,D=[],E=-1,F=null,G=function(){this.debug.log("Attempting play..."),A&&(this.debug.log("Do play."),this.videoModel.play())},H=function(){this.debug.log("Do pause."),this.videoModel.pause()},I=function(a){this.debug.log("Attempting seek..."),A&&(this.debug.log("Do seek: "+a),this.system.notify("setCurrentTime"),this.videoModel.setCurrentTime(a),t&&t.seek(a),v&&v.seek(a))},J=function(a){var b,c=this;if(b="msneedkey"!==a.type?a.type:q,D.push({type:b,initData:a.initData}),this.debug.log("DRM: Key required for - "+b),s&&q&&!C)try{C=c.protectionController.selectKeySystem(q,s)}catch(d){H.call(c),c.debug.log(d),c.errHandler.mediaKeySystemSelectionError(d)}C&&c.protectionController.ensureKeySession(C,b,a.initData)},K=function(a){var b=this,c=null,d=null,e=null,f=null;this.debug.log("DRM: Got a key message..."),c=a.target,d=new Uint16Array(a.message.buffer),e=String.fromCharCode.apply(null,d),f=a.destinationURL,b.protectionController.updateFromMessage(C,c,e,f).fail(function(a){H.call(b),b.debug.log(a),b.errHandler.mediaKeyMessageError(a)})},L=function(){this.debug.log("DRM: Key added.")},M=function(){var a,b=event.target;switch(a="DRM: MediaKeyError - sessionId: "+b.sessionId+" errorCode: "+b.error.code+" systemErrorCode: "+b.error.systemCode+" [",b.error.code){case 1:a+="MEDIA_KEYERR_UNKNOWN - An unspecified error occurred. This value is used for errors that don't match any of the other codes.";break;case 2:a+="MEDIA_KEYERR_CLIENT - The Key System could not be installed or updated.";break;case 3:a+="MEDIA_KEYERR_SERVICE - The message passed into update indicated an error from the license service.";break;case 4:a+="MEDIA_KEYERR_OUTPUT - There is no available output device with the required characteristics for the content protection system.";break;case 5:a+="MEDIA_KEYERR_HARDWARECHANGE - A hardware configuration change caused a content protection error.";break;case 6:a+="MEDIA_KEYERR_DOMAIN - An error occurred in a multi-device domain licensing configuration. The most common error is a failure to join the domain."}a+="]",this.debug.log(a),this.errHandler.mediaKeySessionError(a)},N=function(a){var b=Q.defer(),c=this,d=function(e){c.debug.log("MediaSource is open!"),c.debug.log(e),a.removeEventListener("sourceopen",d),a.removeEventListener("webkitsourceopen",d),b.resolve(a)};return c.debug.log("MediaSource should be closed. The actual readyState is: "+a.readyState),a.addEventListener("sourceopen",d,!1),a.addEventListener("webkitsourceopen",d,!1),c.mediaSourceExt.attachMediaSource(a,c.videoModel),c.debug.log("MediaSource attached to video. Waiting on open..."),b.promise},O=function(){var c=this;t&&t.reset(B),v&&v.reset(B),b&&c.mediaSourceExt.detachMediaSource(c.videoModel),A=!1,C=null,D=[],s=null,t=null,v=null,x=null,q=null,r=null,b=null,a=null},P=function(b,c,d,e){if(b&&c&&d)if(null===t&&null===v&&null===x){var f="No streams to play.";this.errHandler.manifestError(f,"nostreams",a),this.debug.log(f),e.reject()}else this.debug.log("MediaSource initialized!"),e.resolve(!0)},R=function(){this.debug.log("Getting MediaSource ready...");var a=Q.defer(),c=!1,d=!1,e=!1,f=this,g=f.manifestModel.getValue(),h=f.manifestExt.getIsLive(g);return f.debug.log("Gathering information for buffers. (1)"),f.manifestExt.getDuration(g,h).then(function(){f.manifestExt.getVideoData(g,E).then(function(h){return null!==h?(f.debug.log("Create video buffer."),f.manifestExt.getDataIndex(h,g,E).then(function(a){u=a,f.debug.log("Save video track: "+u)}),f.manifestExt.getCodec(h).then(function(a){return f.debug.log("Video codec: "+a),q=a,f.manifestExt.getContentProtectionData(h).then(function(c){if(f.debug.log("Video contentProtection"),c&&!f.capabilities.supportsMediaKeys())return f.errHandler.capabilityError("mediakeys"),Q.when(null);if(s=c,!f.capabilities.supportsCodec(f.videoModel.getElement(),a)){var d="Video Codec ("+a+") is not supported.";return f.errHandler.manifestError(d,"codec",g),f.debug.log(d),Q.when(null)}return f.sourceBufferExt.createSourceBuffer(b,a)})}).then(function(g){null===g?f.debug.log("No buffer was created, skipping video stream."):(t=f.system.getObject("bufferController"),t.initialize("video",E,h,g,f.videoModel,f.requestScheduler,f.fragmentController,b),f.debug.log("Video is ready!")),c=!0,P.call(f,c,d,e,a)},function(){f.errHandler.mediaSourceError("Error creating video source buffer."),c=!0,P.call(f,c,d,e,a)})):(f.debug.log("No video data."),c=!0,P.call(f,c,d,e,a)),f.manifestExt.getAudioDatas(g,E)}).then(function(h){return null!==h&&h.length>0?(f.debug.log("Have audio streams: "+h.length),f.manifestExt.getPrimaryAudioData(g,E).then(function(h){f.manifestExt.getDataIndex(h,g,E).then(function(a){w=a,f.debug.log("Save audio track: "+w)}),f.manifestExt.getCodec(h).then(function(a){return f.debug.log("Audio codec: "+a),r=a,f.manifestExt.getContentProtectionData(h).then(function(c){if(f.debug.log("Audio contentProtection"),c&&!f.capabilities.supportsMediaKeys())return f.errHandler.capabilityError("mediakeys"),Q.when(null);if(s=c,!f.capabilities.supportsCodec(f.videoModel.getElement(),a)){var d="Audio Codec ("+a+") is not supported.";return f.errHandler.manifestError(d,"codec",g),f.debug.log(d),Q.when(null)}return f.sourceBufferExt.createSourceBuffer(b,a)})}).then(function(g){null===g?f.debug.log("No buffer was created, skipping audio stream."):(v=f.system.getObject("bufferController"),v.initialize("audio",E,h,g,f.videoModel,f.requestScheduler,f.fragmentController,b),f.debug.log("Audio is ready!")),d=!0,P.call(f,c,d,e,a)},function(){f.errHandler.mediaSourceError("Error creating audio source buffer."),d=!0,P.call(f,c,d,e,a)})})):(f.debug.log("No audio streams."),d=!0,P.call(f,c,d,e,a)),f.manifestExt.getTextData(g,E)}).then(function(h){var i;null!==h?(f.manifestExt.getDataIndex(h,g,E).then(function(a){y=a,f.debug.log("Save text track: "+y)}),f.manifestExt.getMimeType(h).then(function(a){return i=a,f.sourceBufferExt.createSourceBuffer(b,i)}).then(function(b){null===b?f.debug.log("Source buffer was not created for text track"):(x=f.system.getObject("textController"),x.initialize(E,h,b,f.videoModel),b.hasOwnProperty("initialize")&&b.initialize(i,x),f.debug.log("Text is ready!"),e=!0,P.call(f,c,d,e,a))},function(b){f.debug.log("Error creating text source buffer:"),f.debug.log(b),f.errHandler.mediaSourceError("Error creating text source buffer."),e=!0,P.call(f,c,d,e,a)})):(f.debug.log("No text tracks."),e=!0,P.call(f,c,d,e,a))})}),a.promise},S=function(){var a=this,c=Q.defer(),d=a.manifestModel.getValue(),e=a.manifestExt.getIsLive(d);return a.debug.log("Getting ready for playback..."),a.manifestExt.getDurationForPeriod(E,a.manifestModel.getValue(),e).then(function(a){l=a}),a.manifestExt.getDuration(a.manifestModel.getValue(),e).then(function(c){return a.debug.log("Setting duration: "+c),a.mediaSourceExt.setDuration(b,c)}).then(function(){return a.debug.log("Duration successfully set."),a.manifestExt.getPeriodStart(a.manifestModel.getValue(),E)}).then(function(a){F=a,A=!0,c.resolve(!0)}),c.promise},T=function(){var a=this;a.debug.log("Got loadmetadata event."),c.resolve(null)},U=function(){this.debug.log("Got play event."),A&&(null!==F?(this.debug.log("Starting segment loading at offset: "+F),t&&t.seek(F),v&&v.seek(F),x&&x.seek(F)):(t&&t.start(),v&&v.start(),x&&x.start()))},V=function(){this.debug.log("Got pause event."),this.scheduleWhilePaused||ab.call(this)},W=function(a){var b=a.srcElement.error,c=b.code,d="";if(-1!==c){switch(c){case 1:d="MEDIA_ERR_ABORTED";break;case 2:d="MEDIA_ERR_NETWORK";break;case 3:d="MEDIA_ERR_DECODE";break;case 4:d="MEDIA_ERR_SRC_NOT_SUPPORTED";break;case 5:d="MEDIA_ERR_ENCRYPTED"}B=!0,this.debug.log("Video Element Error: "+d),this.debug.log(b),this.errHandler.mediaSourceError(d),this.reset()}},X=function(){this.debug.log("Got seeking event.");var a=this.videoModel.getCurrentTime();t&&t.seek(a),v&&v.seek(a)},Y=function(){this.debug.log("Seek complete."),this.videoModel.listen("seeking",h),this.videoModel.unlisten("seeked",i)},Z=function(){_.call(this)},$=function(){_.call(this)},_=function(){t&&t.updateBufferState(),v&&v.updateBufferState()},ab=function(){t&&t.stop(),v&&v.stop()},bb=function(d){var e=this;return e.debug.log("Stream start loading."),a=d,e.mediaSourceExt.createMediaSource().then(function(a){return e.debug.log("MediaSource created."),N.call(e,a)}).then(function(a){return b=a,e.debug.log("MediaSource set up."),R.call(e)}).then(function(){return e.debug.log("Start initializing playback."),S.call(e)}).then(function(){return z?(e.debug.log("Playback initialized!"),c.promise):void 0}).then(function(){e.debug.log("element loaded!"),0===E&&G.call(e)})},cb=function(){this.debug.log("Current time has changed, block programmatic seek."),this.videoModel.unlisten("seeking",h),this.videoModel.listen("seeked",i)},db=function(){t&&!t.isBufferingCompleted()||v&&!v.isBufferingCompleted()||b&&this.mediaSourceExt.signalEndOfStream(b)},eb=function(){ab.call(this)},fb=function(){var a,b,c=this,d=c.manifestModel.getValue();c.debug.log("Manifest updated... set new data on buffers."),t&&(a=t.getData(),a&&a.hasOwnProperty("id")?c.manifestExt.getDataForId(a.id,d,E).then(function(a){t.setData(a)}):c.manifestExt.getDataForIndex(u,d,E).then(function(a){t.setData(a)})),v&&(b=v.getData(),b&&b.hasOwnProperty("id")?c.manifestExt.getDataForId(b.id,d,E).then(function(a){v.setData(a)}):c.manifestExt.getDataForIndex(w,d,E).then(function(a){v.setData(a)}))};return{system:void 0,videoModel:void 0,manifestLoader:void 0,manifestModel:void 0,mediaSourceExt:void 0,sourceBufferExt:void 0,bufferExt:void 0,manifestExt:void 0,fragmentController:void 0,abrController:void 0,fragmentExt:void 0,protectionModel:void 0,protectionController:void 0,protectionExt:void 0,capabilities:void 0,debug:void 0,metricsExt:void 0,errHandler:void 0,requestScheduler:void 0,scheduleWhilePaused:void 0,setup:function(){this.system.mapHandler("manifestUpdated",void 0,fb.bind(this)),this.system.mapHandler("setCurrentTime",void 0,cb.bind(this)),this.system.mapHandler("bufferingCompleted",void 0,db.bind(this)),this.system.mapHandler("segmentLoadingFailed",void 0,eb.bind(this)),c=Q.defer(),e=U.bind(this),f=V.bind(this),g=W.bind(this),h=X.bind(this),i=Y.bind(this),k=Z.bind(this),j=$.bind(this),d=T.bind(this)},load:function(a,b){E=b,bb.call(this,a)},setVideoModel:function(a){this.videoModel=a,this.videoModel.listen("play",e),this.videoModel.listen("pause",f),this.videoModel.listen("error",g),this.videoModel.listen("seeking",h),this.videoModel.listen("timeupdate",j),this.videoModel.listen("progress",k),this.videoModel.listen("loadedmetadata",d)},initProtection:function(){m=J.bind(this),n=K.bind(this),o=L.bind(this),p=M.bind(this),this.protectionModel=this.system.getObject("protectionModel"),this.protectionModel.init(this.getVideoModel()),this.protectionController=this.system.getObject("protectionController"),this.protectionController.init(this.videoModel,this.protectionModel),this.protectionModel.listenToNeedKey(m),this.protectionModel.listenToKeyMessage(n),this.protectionModel.listenToKeyError(p),this.protectionModel.listenToKeyAdded(o)},getVideoModel:function(){return this.videoModel},getManifestExt:function(){var a=this;return a.manifestExt},setAutoPlay:function(a){z=a},getAutoPlay:function(){return z},reset:function(){H.call(this),this.videoModel.unlisten("play",e),this.videoModel.unlisten("pause",f),this.videoModel.unlisten("error",g),this.videoModel.unlisten("seeking",h),this.videoModel.unlisten("timeupdate",j),this.videoModel.unlisten("progress",k),this.videoModel.unlisten("loadedmetadata",d),O.call(this),this.protectionController&&this.protectionController.teardownKeySystem(C),this.protectionController=void 0,this.protectionModel=void 0,this.fragmentController=void 0,this.requestScheduler=void 0,c=Q.defer()},getDuration:function(){return l},setPeriodIndex:function(a){E=a},getPeriodIndex:function(){return E},getStartTime:function(){return F},play:G,seek:I,pause:H}},MediaPlayer.dependencies.Stream.prototype={constructor:MediaPlayer.dependencies.Stream},MediaPlayer.dependencies.StreamController=function(){"use strict";var a,b=[],c=4,d=3,e=!0,f=null,g=function(){a.play()},h=function(){a.pause()},i=function(b){a.seek(b)},j=function(a,b){var c=a.getElement(),d=b.getElement();return d.parentNode||c.parentNode.insertBefore(d,c),c.style.width="0px",d.style.width="100%",m(c,d),l(a),k(b),Q.when(!0)},k=function(a){a.listen("seeking",p),a.listen("progress",n),r()&&a.listen("timeupdate",o)},l=function(a){a.unlisten("seeking",p),a.unlisten("progress",n),a.unlisten("timeupdate",o)},m=function(a,b){["controls","loop","muted","playbackRate","volume"].forEach(function(c){b[c]=a[c]})},n=function(){var b=a.getVideoModel().getElement().buffered;if(b.length){var d=b.length-1,e=b.end(d),f=a.getStartTime()+a.getDuration()-e;c>f&&(a.getVideoModel().unlisten("progress",n),q())}},o=function(){if(!a.getVideoModel().getElement().seeking){var b=a.getStartTime()+a.getDuration(),c=a.getVideoModel().getCurrentTime();d>b-c&&v(a,r())}},p=function(){var b=a.getVideoModel().getCurrentTime(),c=s(b);c&&c!==a&&v(a,c,b)},q=function(){var a=r();a&&a.seek(a.getStartTime())},r=function(){var c=a.getPeriodIndex()+1;return ce;e++)if(d=b[e],c+=d.getDuration(),c>a)return d},t=function(){var a=this.system.getObject("videoModel"),b=document.createElement("video");return a.setElement(b),a},u=function(a){a.parentNode&&a.parentNode.removeChild(a)},v=function(b,c,d){b&&c&&b!==c&&Q.when(f||!0).then(function(){b.pause(),a=c,f=j(b.getVideoModel(),c.getVideoModel()),d?i(b.getVideoModel().getCurrentTime()):i(c.getStartTime()),g()})};return{system:void 0,videoModel:void 0,manifestLoader:void 0,manifestUpdater:void 0,manifestModel:void 0,mediaSourceExt:void 0,sourceBufferExt:void 0,bufferExt:void 0,manifestExt:void 0,fragmentController:void 0,abrController:void 0,fragmentExt:void 0,capabilities:void 0,debug:void 0,metricsExt:void 0,errHandler:void 0,getManifestExt:function(){return a.getManifestExt()},setAutoPlay:function(a){e=a},getAutoPlay:function(){return e},getVideoModel:function(){return this.videoModel},setVideoModel:function(a){this.videoModel=a},load:function(c){var d,f=this;f.manifestLoader.load(c).then(function(c){f.manifestModel.setValue(c),f.debug.log("Manifest has loaded."),f.debug.log(f.manifestModel.getValue()),f.manifestUpdater.init(),f.manifestExt.getPeriodCount(c).then(function(g){for(var h=0;g>h;h++)d=f.system.getObject("stream"),d.setVideoModel(0===h?f.videoModel:t.call(f)),d.initProtection(),d.setAutoPlay(e),d.load(c,h),b.push(d);a=b[0],k(a.getVideoModel())})},function(){f.reset()})},reset:function(){a&&l(a.getVideoModel());for(var c=0,d=b.length;d>c;c++){var e=b[c];e.reset(),e!==a&&u(e.getVideoModel().getElement())}b=[],this.manifestUpdater.stop(),this.manifestModel.setValue(null),f=null,a=null},play:g,seek:i,pause:h}},MediaPlayer.dependencies.StreamController.prototype={constructor:MediaPlayer.dependencies.StreamController},MediaPlayer.models.VideoModel=function(){"use strict";var a,b=[],c=function(){return b.length>0},d=function(c){null!==c&&b[c]!==!0&&(b.push(c),b[c]=!0,a.playbackRate=0)},e=function(d){if(null!==d){b[d]=!1;var e=b.indexOf(d);-1!==e&&b.splice(e,1),c()===!1&&(a.playbackRate=1)}},f=function(a,b){b?d(a):e(a)};return{system:void 0,setup:function(){},play:function(){a.play()},pause:function(){a.pause()},isPaused:function(){return a.paused},getPlaybackRate:function(){return a.playbackRate},setPlaybackRate:function(b){a.playbackRate=b},getCurrentTime:function(){return a.currentTime},setCurrentTime:function(b){a.currentTime!=b&&(a.currentTime=b)},listen:function(b,c){a.addEventListener(b,c,!1)},unlisten:function(b,c){a.removeEventListener(b,c,!1)},getElement:function(){return a},setElement:function(b){a=b},setSource:function(b){a.src=b},stallStream:f,isStalled:c}},MediaPlayer.models.VideoModel.prototype={constructor:MediaPlayer.models.VideoModel},MediaPlayer.dependencies.VideoModelExtensions=function(){"use strict";return{getDroppedFrames:function(a){var b=null!==a.webkitDroppedFrameCount,c=-1;return b&&(c=a.webkitDroppedFrameCount),c}}},MediaPlayer.dependencies.VideoModelExtensions.prototype={constructor:MediaPlayer.dependencies.VideoModelExtensions},MediaPlayer.dependencies.TextController=function(){var a,b,c="LOADING",d="READY",e=!1,f=-1,g=d,h=function(a){this.debug.log("TextController setState to:"+a),g=a},i=function(){if(e&&g===d){var b=this;h.call(b,c),b.indexHandler.getInitRequest(0,a).then(function(a){b.debug.log("Loading text track initialization: "+a.url),b.debug.log(a),b.fragmentLoader.load(a).then(k.bind(b,a),l.bind(b,a)),h.call(b,c)})}},j=function(){i.call(this)},k=function(a,c){var d=this;d.debug.log(" Text track Bytes finished loading: "+a.url),d.fragmentController.process(c.data).then(function(a){null!==a&&(d.debug.log("Push text track bytes: "+a.byteLength),d.sourceBufferExt.append(b,a,d.videoModel))})},l=function(){};return{videoModel:void 0,fragmentLoader:void 0,fragmentController:void 0,indexHandler:void 0,sourceBufferExt:void 0,debug:void 0,initialize:function(a,b,c,d){var f=this;f.setVideoModel(d),f.setPeriodIndex(a),f.setData(b),f.setBuffer(c),e=!0},getPeriodIndex:function(){return f},setPeriodIndex:function(a){f=a},getVideoModel:function(){return this.videoModel},setVideoModel:function(a){this.videoModel=a},getData:function(){return a},setData:function(b){a=b},getBuffer:function(){return b},setBuffer:function(a){b=a},reset:function(a,c){a||(this.sourceBufferExt.abort(c,b),this.sourceBufferExt.removeSourceBuffer(c,b))},start:j}},MediaPlayer.dependencies.TextController.prototype={constructor:MediaPlayer.dependencies.TextController},MediaPlayer.utils.TextTrackExtensions=function(){"use strict";return{addTextTrack:function(a,b,c,d,e){var f=a.addTextTrack("captions",c,d);f.default=e,f.mode="showing";for(var g in b){var h=b[g];f.addCue(new TextTrackCue(h.start,h.end,h.data))}return Q.when(f)},deleteCues:function(a){for(var b=a.textTracks[0],c=b.cues,d=c.length;d>=0;d--)b.removeCue(c[d]);b.mode="disabled"}}},MediaPlayer.dependencies.TextVTTSourceBuffer=function(){var a,b,c;return{system:void 0,eventBus:void 0,initialize:function(d,e){c=d,a=e.getVideoModel().getElement(),b=e.getData()},append:function(c){var d=this;d.getParser().parse(String.fromCharCode.apply(null,new Uint16Array(c))).then(function(c){var e=b.Representation_asArray[0].id,f=b.lang;d.getTextTrackExtensions().addTextTrack(a,c,e,f,!0).then(function(){d.eventBus.dispatchEvent({type:"updateend"})})})},abort:function(){this.getTextTrackExtensions().deleteCues(a)},getParser:function(){var a;return"text/vtt"===c&&(a=this.system.getObject("vttParser")),a},getTextTrackExtensions:function(){return this.system.getObject("textTrackExtensions")},addEventListener:function(a,b,c){this.eventBus.addEventListener(a,b,c)},removeEventListener:function(a,b,c){this.eventBus.removeEventListener(a,b,c)}}},MediaPlayer.dependencies.TextVTTSourceBuffer.prototype={constructor:MediaPlayer.dependencies.TextVTTSourceBuffer},MediaPlayer.utils.VTTParser=function(){"use strict";var a=function(a){var b=a.split(":"),c=b.length-1;return a=60*parseInt(b[c-1],10)+parseFloat(b[c],10),2===c&&(a+=3600*parseInt(b[0],10)),a};return{parse:function(b){var c,d=/(?:\r\n|\r|\n)/gm,e=/-->/,f=/(^[\s]+|[\s]+$)/g,g=[];b=b.split(d),c=b.length;for(var h=0;c>h;h++){var i=b[h];if(i.length>0&&"WEBVTT"!==i&&i.match(e)){var j=i.split(e),k=b[h+1];g.push({start:a(j[0].replace(f,"")),end:a(j[1].replace(f,"")),data:k})}}return Q.when(g)}}},MediaPlayer.rules.BaseRulesCollection=function(){"use strict";var a=[];return{downloadRatioRule:void 0,insufficientBufferRule:void 0,getRules:function(){return Q.when(a)},setup:function(){var a=this;a.getRules().then(function(b){b.push(a.downloadRatioRule),b.push(a.insufficientBufferRule)})}}},MediaPlayer.rules.BaseRulesCollection.prototype={constructor:MediaPlayer.rules.BaseRulesCollection},MediaPlayer.rules.DownloadRatioRule=function(){"use strict";var a=function(a,b,c){var d=this,e=Q.defer();return d.manifestExt.getRepresentationFor(a,c).then(function(a){d.manifestExt.getBandwidth(a).then(function(a){e.resolve(a/b)})}),e.promise};return{debug:void 0,manifestExt:void 0,checkIndex:function(b,c,d){var e,f,g,h,i,j,k,l,m,n,o=this,p=c.HttpList,q=.75;return o.debug.log("Checking download ratio rule..."),c?null===p||void 0===p||0===p.length?(o.debug.log("No requests made for this stream yet, bailing."),Q.when(new MediaPlayer.rules.SwitchRequest)):(e=p[p.length-1],g=(e.tfinish.getTime()-e.trequest.getTime())/1e3,f=(e.tfinish.getTime()-e.tresponse.getTime())/1e3,0>=g?(o.debug.log("Don't know how long the download of the last fragment took, bailing."),Q.when(new MediaPlayer.rules.SwitchRequest)):null===e.mediaduration||void 0===e.mediaduration||e.mediaduration<=0?(o.debug.log("Don't know the duration of the last media fragment, bailing."),Q.when(new MediaPlayer.rules.SwitchRequest)):(k=Q.defer(),i=e.mediaduration/g,h=e.mediaduration/f*q,isNaN(h)||isNaN(i)?(o.debug.log("Total time: "+g+"s"),o.debug.log("Download time: "+f+"s"),o.debug.log("The ratios are NaN, bailing."),Q.when(new MediaPlayer.rules.SwitchRequest)):(o.debug.log("Total ratio: "+i),o.debug.log("Download ratio: "+h),o.debug.log("Download ratio: "+h),isNaN(h)?(o.debug.log("Invalid ratio, bailing."),k.resolve(new MediaPlayer.rules.SwitchRequest)):1>h?(o.debug.log("Download ratio is poor."),b>0?(o.debug.log("We are not at the lowest bitrate, so switch down."),o.manifestExt.getRepresentationFor(b-1,d).then(function(a){o.manifestExt.getBandwidth(a).then(function(a){o.manifestExt.getRepresentationFor(b,d).then(function(c){o.manifestExt.getBandwidth(c).then(function(c){j=a/c,o.debug.log("Switch ratio: "+j),j>h?(o.debug.log("Things must be going pretty bad, switch all the way down."),k.resolve(new MediaPlayer.rules.SwitchRequest(0))):(o.debug.log("Things could be better, so just switch down one index."),k.resolve(new MediaPlayer.rules.SwitchRequest(b-1))) -})})})})):(o.debug.log("We are at the lowest bitrate and cannot switch down, use current."),k.resolve(new MediaPlayer.rules.SwitchRequest(b)))):(o.debug.log("Download ratio is good."),o.manifestExt.getRepresentationCount(d).then(function(c){c-=1,c>b?(o.debug.log("We are not at the highest bitrate, so switch up."),o.manifestExt.getRepresentationFor(b+1,d).then(function(e){o.manifestExt.getBandwidth(e).then(function(e){o.manifestExt.getRepresentationFor(b,d).then(function(f){o.manifestExt.getBandwidth(f).then(function(f){if(j=e/f,o.debug.log("Switch ratio: "+j),h>=j)if(h>1e3)o.debug.log("Tons of bandwidth available, go all the way up."),k.resolve(new MediaPlayer.rules.SwitchRequest(c-1));else if(h>100)o.debug.log("Just enough bandwidth available, switch up one."),k.resolve(new MediaPlayer.rules.SwitchRequest(b+1));else{for(o.debug.log("Not exactly sure where to go, so do some math."),m=-1,l=[];(m+=1)m&&!(hb&&(i=MediaPlayer.rules.SwitchRequest.prototype.STRONG,g.debug.log("Apply STRONG to buffer rule.")),h?(g.debug.log("The buffer ran dry recently, switch down."),Q.when(new MediaPlayer.rules.SwitchRequest(c-1,i))):a>b?(g.debug.log("Too many dry buffer hits, quit switching bitrates."),Q.when(new MediaPlayer.rules.SwitchRequest(c,i))):Q.when(new MediaPlayer.rules.SwitchRequest(MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE,i)))))}}},MediaPlayer.rules.InsufficientBufferRule.prototype={constructor:MediaPlayer.rules.InsufficientBufferRule},MediaPlayer.rules.LimitSwitchesRule=function(){"use strict";var a=10,b=2e4,c=5,d=0;return{debug:void 0,checkIndex:function(e,f){if(d>0)return d-=1,Q.when(new MediaPlayer.rules.SwitchRequest(e,MediaPlayer.rules.SwitchRequest.prototype.STRONG));var g,h,i,j=this,k=!1,l=(new Date).getTime(),m=f.RepSwitchList.length;for(j.debug.log("Checking limit switches rule..."),i=m-1;i>=0;i-=1){if(g=f.RepSwitchList[i],h=l-g.t.getTime(),h>=b){j.debug.log("Reached time limit, bailing.");break}if(i>=a){j.debug.log("Found too many switches within validation time, force the stream to not change."),k=!0;break}}return k?(j.debug.log("Wait some time before allowing another switch."),d=c,Q.when(new MediaPlayer.rules.SwitchRequest(e,MediaPlayer.rules.SwitchRequest.prototype.STRONG))):Q.when(new MediaPlayer.rules.SwitchRequest(MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE,MediaPlayer.rules.SwitchRequest.prototype.STRONG))}}},MediaPlayer.rules.LimitSwitchesRule.prototype={constructor:MediaPlayer.rules.LimitSwitchesRule},MediaPlayer.rules.SwitchRequest=function(a,b){"use strict";this.quality=a,this.priority=b,void 0===this.quality&&(this.quality=999),void 0===this.priority&&(this.priority=.5)},MediaPlayer.rules.SwitchRequest.prototype={constructor:MediaPlayer.rules.SwitchRequest,NO_CHANGE:999,DEFAULT:.5,STRONG:1,WEAK:0},MediaPlayer.models.MetricsList=function(){"use strict";return{TcpList:[],HttpList:[],RepSwitchList:[],BufferLevel:[],PlayList:[],DroppedFrames:[]}},MediaPlayer.models.MetricsList.prototype={constructor:MediaPlayer.models.MetricsList},MediaPlayer.vo.SegmentRequest=function(){"use strict";this.action="download",this.startTime=0/0,this.streamType=null,this.type=null,this.duration=0/0,this.timescale=0/0,this.range=null,this.url=null,this.requestStartDate=null,this.firstByteDate=null,this.requestEndDate=null,this.deferred=null,this.quality=0/0,this.index=0/0},MediaPlayer.vo.SegmentRequest.prototype={constructor:MediaPlayer.vo.SegmentRequest,ACTION_DOWNLOAD:"download",ACTION_COMPLETE:"complete"},MediaPlayer.vo.metrics.BufferLevel=function(){"use strict";this.t=null,this.level=null},MediaPlayer.vo.metrics.BufferLevel.prototype={constructor:MediaPlayer.vo.metrics.BufferLevel},MediaPlayer.vo.metrics.DroppedFrames=function(){"use strict";this.time=null,this.droppedFrames=null},MediaPlayer.vo.metrics.DroppedFrames.prototype={constructor:MediaPlayer.vo.metrics.DroppedFrames},MediaPlayer.vo.metrics.HTTPRequest=function(){"use strict";this.tcpid=null,this.type=null,this.url=null,this.actualurl=null,this.range=null,this.trequest=null,this.tresponse=null,this.tfinish=null,this.responsecode=null,this.interval=null,this.mediaduration=null,this.trace=[]},MediaPlayer.vo.metrics.HTTPRequest.prototype={constructor:MediaPlayer.vo.metrics.HTTPRequest},MediaPlayer.vo.metrics.HTTPRequest.Trace=function(){"use strict";this.s=null,this.d=null,this.b=[]},MediaPlayer.vo.metrics.HTTPRequest.Trace.prototype={constructor:MediaPlayer.vo.metrics.HTTPRequest.Trace},MediaPlayer.vo.metrics.PlayList=function(){"use strict";this.start=null,this.mstart=null,this.starttype=null,this.trace=[]},MediaPlayer.vo.metrics.PlayList.Trace=function(){"use strict";this.representationid=null,this.subreplevel=null,this.start=null,this.mstart=null,this.duration=null,this.playbackspeed=null,this.stopreason=null},MediaPlayer.vo.metrics.PlayList.prototype={constructor:MediaPlayer.vo.metrics.PlayList},MediaPlayer.vo.metrics.PlayList.INITIAL_PLAY_START_REASON="initial_start",MediaPlayer.vo.metrics.PlayList.SEEK_START_REASON="seek",MediaPlayer.vo.metrics.PlayList.Trace.prototype={constructor:MediaPlayer.vo.metrics.PlayList.Trace()},MediaPlayer.vo.metrics.PlayList.Trace.USER_REQUEST_STOP_REASON="user_request",MediaPlayer.vo.metrics.PlayList.Trace.REPRESENTATION_SWITCH_STOP_REASON="representation_switch",MediaPlayer.vo.metrics.PlayList.Trace.END_OF_CONTENT_STOP_REASON="end_of_content",MediaPlayer.vo.metrics.PlayList.Trace.REBUFFERING_REASON="rebuffering",MediaPlayer.vo.metrics.RepresentationSwitch=function(){"use strict";this.t=null,this.mt=null,this.to=null,this.lto=null},MediaPlayer.vo.metrics.RepresentationSwitch.prototype={constructor:MediaPlayer.vo.metrics.RepresentationSwitch},MediaPlayer.vo.metrics.TCPConnection=function(){"use strict";this.tcpid=null,this.dest=null,this.topen=null,this.tclose=null,this.tconnect=null},MediaPlayer.vo.metrics.TCPConnection.prototype={constructor:MediaPlayer.vo.metrics.TCPConnection}; \ No newline at end of file +})})})})):(o.debug.log("We are at the lowest bitrate and cannot switch down, use current."),k.resolve(new MediaPlayer.rules.SwitchRequest(b)))):(o.debug.log("Download ratio is good."),o.manifestExt.getRepresentationCount(d).then(function(c){c-=1,c>b?(o.debug.log("We are not at the highest bitrate, so switch up."),o.manifestExt.getRepresentationFor(b+1,d).then(function(e){o.manifestExt.getBandwidth(e).then(function(e){o.manifestExt.getRepresentationFor(b,d).then(function(f){o.manifestExt.getBandwidth(f).then(function(f){if(j=e/f,o.debug.log("Switch ratio: "+j),h>=j)if(h>1e3)o.debug.log("Tons of bandwidth available, go all the way up."),k.resolve(new MediaPlayer.rules.SwitchRequest(c-1));else if(h>100)o.debug.log("Just enough bandwidth available, switch up one."),k.resolve(new MediaPlayer.rules.SwitchRequest(b+1));else{for(o.debug.log("Not exactly sure where to go, so do some math."),m=-1,l=[];(m+=1)m&&!(hb&&(i=MediaPlayer.rules.SwitchRequest.prototype.STRONG,g.debug.log("Apply STRONG to buffer rule.")),h?(g.debug.log("The buffer ran dry recently, switch down."),Q.when(new MediaPlayer.rules.SwitchRequest(c-1,i))):a>b?(g.debug.log("Too many dry buffer hits, quit switching bitrates."),Q.when(new MediaPlayer.rules.SwitchRequest(c,i))):Q.when(new MediaPlayer.rules.SwitchRequest(MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE,i)))))}}},MediaPlayer.rules.InsufficientBufferRule.prototype={constructor:MediaPlayer.rules.InsufficientBufferRule},MediaPlayer.rules.LimitSwitchesRule=function(){"use strict";var a=10,b=2e4,c=5,d=0;return{debug:void 0,checkIndex:function(e,f){if(d>0)return d-=1,Q.when(new MediaPlayer.rules.SwitchRequest(e,MediaPlayer.rules.SwitchRequest.prototype.STRONG));var g,h,i,j=this,k=!1,l=(new Date).getTime(),m=f.RepSwitchList.length;for(j.debug.log("Checking limit switches rule..."),i=m-1;i>=0;i-=1){if(g=f.RepSwitchList[i],h=l-g.t.getTime(),h>=b){j.debug.log("Reached time limit, bailing.");break}if(i>=a){j.debug.log("Found too many switches within validation time, force the stream to not change."),k=!0;break}}return k?(j.debug.log("Wait some time before allowing another switch."),d=c,Q.when(new MediaPlayer.rules.SwitchRequest(e,MediaPlayer.rules.SwitchRequest.prototype.STRONG))):Q.when(new MediaPlayer.rules.SwitchRequest(MediaPlayer.rules.SwitchRequest.prototype.NO_CHANGE,MediaPlayer.rules.SwitchRequest.prototype.STRONG))}}},MediaPlayer.rules.LimitSwitchesRule.prototype={constructor:MediaPlayer.rules.LimitSwitchesRule},MediaPlayer.rules.SwitchRequest=function(a,b){"use strict";this.quality=a,this.priority=b,void 0===this.quality&&(this.quality=999),void 0===this.priority&&(this.priority=.5)},MediaPlayer.rules.SwitchRequest.prototype={constructor:MediaPlayer.rules.SwitchRequest,NO_CHANGE:999,DEFAULT:.5,STRONG:1,WEAK:0},MediaPlayer.models.MetricsList=function(){"use strict";return{TcpList:[],HttpList:[],RepSwitchList:[],BufferLevel:[],PlayList:[],DroppedFrames:[]}},MediaPlayer.models.MetricsList.prototype={constructor:MediaPlayer.models.MetricsList},MediaPlayer.vo.SegmentRequest=function(){"use strict";this.action="download",this.startTime=0/0,this.streamType=null,this.type=null,this.duration=0/0,this.timescale=0/0,this.range=null,this.url=null,this.requestStartDate=null,this.firstByteDate=null,this.requestEndDate=null,this.deferred=null,this.quality=0/0,this.index=0/0},MediaPlayer.vo.SegmentRequest.prototype={constructor:MediaPlayer.vo.SegmentRequest,ACTION_DOWNLOAD:"download",ACTION_COMPLETE:"complete"},MediaPlayer.vo.metrics.BufferLevel=function(){"use strict";this.t=null,this.level=null},MediaPlayer.vo.metrics.BufferLevel.prototype={constructor:MediaPlayer.vo.metrics.BufferLevel},MediaPlayer.vo.metrics.DroppedFrames=function(){"use strict";this.time=null,this.droppedFrames=null},MediaPlayer.vo.metrics.DroppedFrames.prototype={constructor:MediaPlayer.vo.metrics.DroppedFrames},MediaPlayer.vo.metrics.HTTPRequest=function(){"use strict";this.tcpid=null,this.type=null,this.url=null,this.actualurl=null,this.range=null,this.trequest=null,this.tresponse=null,this.tfinish=null,this.responsecode=null,this.interval=null,this.mediaduration=null,this.trace=[]},MediaPlayer.vo.metrics.HTTPRequest.prototype={constructor:MediaPlayer.vo.metrics.HTTPRequest},MediaPlayer.vo.metrics.HTTPRequest.Trace=function(){"use strict";this.s=null,this.d=null,this.b=[]},MediaPlayer.vo.metrics.HTTPRequest.Trace.prototype={constructor:MediaPlayer.vo.metrics.HTTPRequest.Trace},MediaPlayer.vo.metrics.PlayList=function(){"use strict";this.start=null,this.mstart=null,this.starttype=null,this.trace=[]},MediaPlayer.vo.metrics.PlayList.Trace=function(){"use strict";this.representationid=null,this.subreplevel=null,this.start=null,this.mstart=null,this.duration=null,this.playbackspeed=null,this.stopreason=null},MediaPlayer.vo.metrics.PlayList.prototype={constructor:MediaPlayer.vo.metrics.PlayList},MediaPlayer.vo.metrics.PlayList.INITIAL_PLAY_START_REASON="initial_start",MediaPlayer.vo.metrics.PlayList.SEEK_START_REASON="seek",MediaPlayer.vo.metrics.PlayList.Trace.prototype={constructor:MediaPlayer.vo.metrics.PlayList.Trace()},MediaPlayer.vo.metrics.PlayList.Trace.USER_REQUEST_STOP_REASON="user_request",MediaPlayer.vo.metrics.PlayList.Trace.REPRESENTATION_SWITCH_STOP_REASON="representation_switch",MediaPlayer.vo.metrics.PlayList.Trace.END_OF_CONTENT_STOP_REASON="end_of_content",MediaPlayer.vo.metrics.PlayList.Trace.REBUFFERING_REASON="rebuffering",MediaPlayer.vo.metrics.RepresentationSwitch=function(){"use strict";this.t=null,this.mt=null,this.to=null,this.lto=null},MediaPlayer.vo.metrics.RepresentationSwitch.prototype={constructor:MediaPlayer.vo.metrics.RepresentationSwitch},MediaPlayer.vo.metrics.TCPConnection=function(){"use strict";this.tcpid=null,this.dest=null,this.topen=null,this.tclose=null,this.tconnect=null},MediaPlayer.vo.metrics.TCPConnection.prototype={constructor:MediaPlayer.vo.metrics.TCPConnection}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImRhc2guYWxsLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxBQUxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZGFzaC5hbGwuanMiLCJzb3VyY2VzQ29udGVudCI6WyJmdW5jdGlvbiBYMkpTKGEsYixjKXtmdW5jdGlvbiBkKGEpe3ZhciBiPWEubG9jYWxOYW1lO3JldHVybiBudWxsPT1iJiYoYj1hLmJhc2VOYW1lKSwobnVsbD09Ynx8XCJcIj09YikmJihiPWEubm9kZU5hbWUpLGJ9ZnVuY3Rpb24gZShhKXtyZXR1cm4gYS5wcmVmaXh9ZnVuY3Rpb24gZihhKXtyZXR1cm5cInN0cmluZ1wiPT10eXBlb2YgYT9hLnJlcGxhY2UoLyYvZyxcIiZhbXA7XCIpLnJlcGxhY2UoLzwvZyxcIiZsdDtcIikucmVwbGFjZSgvPi9nLFwiJmd0O1wiKS5yZXBsYWNlKC9cIi9nLFwiJnF1b3Q7XCIpLnJlcGxhY2UoLycvZyxcIiYjeDI3O1wiKS5yZXBsYWNlKC9cXC8vZyxcIiYjeDJGO1wiKTphfWZ1bmN0aW9uIGcoYSl7cmV0dXJuIGEucmVwbGFjZSgvJmFtcDsvZyxcIiZcIikucmVwbGFjZSgvJmx0Oy9nLFwiPFwiKS5yZXBsYWNlKC8mZ3Q7L2csXCI+XCIpLnJlcGxhY2UoLyZxdW90Oy9nLCdcIicpLnJlcGxhY2UoLyYjeDI3Oy9nLFwiJ1wiKS5yZXBsYWNlKC8mI3gyRjsvZyxcIi9cIil9ZnVuY3Rpb24gaChmKXtpZihmLm5vZGVUeXBlPT11LkRPQ1VNRU5UX05PREUpe3ZhciBpLGosayxsPWYuZmlyc3RDaGlsZDtmb3Ioaj0wLGs9Zi5jaGlsZE5vZGVzLmxlbmd0aDtrPmo7ais9MSlpZihmLmNoaWxkTm9kZXNbal0ubm9kZVR5cGUhPT11LkNPTU1FTlRfTk9ERSl7bD1mLmNoaWxkTm9kZXNbal07YnJlYWt9aWYoYylpPWgobCk7ZWxzZXtpPXt9O3ZhciBtPWQobCk7aVttXT1oKGwpfXJldHVybiBpfWlmKGYubm9kZVR5cGU9PXUuRUxFTUVOVF9OT0RFKXt2YXIgaT1uZXcgT2JqZWN0O2kuX19jbnQ9MDtmb3IodmFyIG49Zi5jaGlsZE5vZGVzLG89MDtvPG4ubGVuZ3RoO28rKyl7dmFyIGw9bi5pdGVtKG8pLG09ZChsKTtpZihpLl9fY250KyssbnVsbD09aVttXSlpW21dPWgobCksaVttK1wiX2FzQXJyYXlcIl09bmV3IEFycmF5KDEpLGlbbStcIl9hc0FycmF5XCJdWzBdPWlbbV07ZWxzZXtpZihudWxsIT1pW21dJiYhKGlbbV1pbnN0YW5jZW9mIEFycmF5KSl7dmFyIHA9aVttXTtpW21dPW5ldyBBcnJheSxpW21dWzBdPXAsaVttK1wiX2FzQXJyYXlcIl09aVttXX1mb3IodmFyIHE9MDtudWxsIT1pW21dW3FdOylxKys7aVttXVtxXT1oKGwpfX1mb3IodmFyIHI9MDtyPGYuYXR0cmlidXRlcy5sZW5ndGg7cisrKXt2YXIgcz1mLmF0dHJpYnV0ZXMuaXRlbShyKTtpLl9fY250Kys7Zm9yKHZhciB2PXMudmFsdWUsdz0wLHg9YS5sZW5ndGg7eD53O3crKyl7dmFyIHk9YVt3XTt5LnRlc3QuY2FsbCh0aGlzLHMudmFsdWUpJiYodj15LmNvbnZlcnRlci5jYWxsKHRoaXMscy52YWx1ZSkpfWlbYitzLm5hbWVdPXZ9dmFyIHo9ZShmKTtyZXR1cm4gbnVsbCE9eiYmXCJcIiE9eiYmKGkuX19jbnQrKyxpLl9fcHJlZml4PXopLDE9PWkuX19jbnQmJm51bGwhPWlbXCIjdGV4dFwiXSYmKGk9aVtcIiN0ZXh0XCJdKSxudWxsIT1pW1wiI3RleHRcIl0mJihpLl9fdGV4dD1pW1wiI3RleHRcIl0sdCYmKGkuX190ZXh0PWcoaS5fX3RleHQpKSxkZWxldGUgaVtcIiN0ZXh0XCJdLGRlbGV0ZSBpW1wiI3RleHRfYXNBcnJheVwiXSksbnVsbCE9aVtcIiNjZGF0YS1zZWN0aW9uXCJdJiYoaS5fX2NkYXRhPWlbXCIjY2RhdGEtc2VjdGlvblwiXSxkZWxldGUgaVtcIiNjZGF0YS1zZWN0aW9uXCJdLGRlbGV0ZSBpW1wiI2NkYXRhLXNlY3Rpb25fYXNBcnJheVwiXSksKG51bGwhPWkuX190ZXh0fHxudWxsIT1pLl9fY2RhdGEpJiYoaS50b1N0cmluZz1mdW5jdGlvbigpe3JldHVybihudWxsIT10aGlzLl9fdGV4dD90aGlzLl9fdGV4dDpcIlwiKSsobnVsbCE9dGhpcy5fX2NkYXRhP3RoaXMuX19jZGF0YTpcIlwiKX0pLGl9cmV0dXJuIGYubm9kZVR5cGU9PXUuVEVYVF9OT0RFfHxmLm5vZGVUeXBlPT11LkNEQVRBX1NFQ1RJT05fTk9ERT9mLm5vZGVWYWx1ZTpmLm5vZGVUeXBlPT11LkNPTU1FTlRfTk9ERT9udWxsOnZvaWQgMH1mdW5jdGlvbiBpKGEsYixjLGQpe3ZhciBlPVwiPFwiKyhudWxsIT1hJiZudWxsIT1hLl9fcHJlZml4P2EuX19wcmVmaXgrXCI6XCI6XCJcIikrYjtpZihudWxsIT1jKWZvcih2YXIgZj0wO2Y8Yy5sZW5ndGg7ZisrKXt2YXIgZz1jW2ZdLGg9YVtnXTtlKz1cIiBcIitnLnN1YnN0cigxKStcIj0nXCIraCtcIidcIn1yZXR1cm4gZSs9ZD9cIi8+XCI6XCI+XCJ9ZnVuY3Rpb24gaihhLGIpe3JldHVyblwiPC9cIisobnVsbCE9YS5fX3ByZWZpeD9hLl9fcHJlZml4K1wiOlwiOlwiXCIpK2IrXCI+XCJ9ZnVuY3Rpb24gayhhLGIpe3JldHVybi0xIT09YS5pbmRleE9mKGIsYS5sZW5ndGgtYi5sZW5ndGgpfWZ1bmN0aW9uIGwoYSxiKXtyZXR1cm4gayhiLnRvU3RyaW5nKCksXCJfYXNBcnJheVwiKXx8MD09Yi50b1N0cmluZygpLmluZGV4T2YoXCJfXCIpfHxhW2JdaW5zdGFuY2VvZiBGdW5jdGlvbj8hMDohMX1mdW5jdGlvbiBtKGEpe3ZhciBiPTA7aWYoYSBpbnN0YW5jZW9mIE9iamVjdClmb3IodmFyIGMgaW4gYSlsKGEsYyl8fGIrKztyZXR1cm4gYn1mdW5jdGlvbiBuKGEpe3ZhciBiPVtdO2lmKGEgaW5zdGFuY2VvZiBPYmplY3QpZm9yKHZhciBjIGluIGEpLTE9PWMudG9TdHJpbmcoKS5pbmRleE9mKFwiX19cIikmJjA9PWMudG9TdHJpbmcoKS5pbmRleE9mKFwiX1wiKSYmYi5wdXNoKGMpO3JldHVybiBifWZ1bmN0aW9uIG8oYSl7dmFyIGI9XCJcIjtyZXR1cm4gbnVsbCE9YS5fX2NkYXRhJiYoYis9XCI8IVtDREFUQVtcIithLl9fY2RhdGErXCJdXT5cIiksbnVsbCE9YS5fX3RleHQmJihiKz10P2YoYS5fX3RleHQpOmEuX190ZXh0KSxifWZ1bmN0aW9uIHAoYSl7dmFyIGI9XCJcIjtyZXR1cm4gYSBpbnN0YW5jZW9mIE9iamVjdD9iKz1vKGEpOm51bGwhPWEmJihiKz10P2YoYSk6YSksYn1mdW5jdGlvbiBxKGEsYixjKXt2YXIgZD1cIlwiO2lmKDA9PWEubGVuZ3RoKWQrPWkoYSxiLGMsITApO2Vsc2UgZm9yKHZhciBlPTA7ZTxhLmxlbmd0aDtlKyspZCs9aShhW2VdLGIsbihhW2VdKSwhMSksZCs9cihhW2VdKSxkKz1qKGFbZV0sYik7cmV0dXJuIGR9ZnVuY3Rpb24gcihhKXt2YXIgYj1cIlwiLGM9bShhKTtpZihjPjApZm9yKHZhciBkIGluIGEpaWYoIWwoYSxkKSl7dmFyIGU9YVtkXSxmPW4oZSk7aWYobnVsbD09ZXx8dm9pZCAwPT1lKWIrPWkoZSxkLGYsITApO2Vsc2UgaWYoZSBpbnN0YW5jZW9mIE9iamVjdClpZihlIGluc3RhbmNlb2YgQXJyYXkpYis9cShlLGQsZik7ZWxzZXt2YXIgZz1tKGUpO2c+MHx8bnVsbCE9ZS5fX3RleHR8fG51bGwhPWUuX19jZGF0YT8oYis9aShlLGQsZiwhMSksYis9cihlKSxiKz1qKGUsZCkpOmIrPWkoZSxkLGYsITApfWVsc2UgYis9aShlLGQsZiwhMSksYis9cChlKSxiKz1qKGUsZCl9cmV0dXJuIGIrPXAoYSl9KG51bGw9PT1ifHx2b2lkIDA9PT1iKSYmKGI9XCJfXCIpLChudWxsPT09Y3x8dm9pZCAwPT09YykmJihjPSExKTt2YXIgcz1cIjEuMC4xMVwiLHQ9ITEsdT17RUxFTUVOVF9OT0RFOjEsVEVYVF9OT0RFOjMsQ0RBVEFfU0VDVElPTl9OT0RFOjQsQ09NTUVOVF9OT0RFOjgsRE9DVU1FTlRfTk9ERTo5fTt0aGlzLnBhcnNlWG1sU3RyaW5nPWZ1bmN0aW9uKGEpe3ZhciBiO2lmKHdpbmRvdy5ET01QYXJzZXIpe3ZhciBjPW5ldyB3aW5kb3cuRE9NUGFyc2VyO2I9Yy5wYXJzZUZyb21TdHJpbmcoYSxcInRleHQveG1sXCIpfWVsc2UgMD09YS5pbmRleE9mKFwiPD9cIikmJihhPWEuc3Vic3RyKGEuaW5kZXhPZihcIj8+XCIpKzIpKSxiPW5ldyBBY3RpdmVYT2JqZWN0KFwiTWljcm9zb2Z0LlhNTERPTVwiKSxiLmFzeW5jPVwiZmFsc2VcIixiLmxvYWRYTUwoYSk7cmV0dXJuIGJ9LHRoaXMueG1sMmpzb249ZnVuY3Rpb24oYSl7cmV0dXJuIGgoYSl9LHRoaXMueG1sX3N0cjJqc29uPWZ1bmN0aW9uKGEpe3ZhciBiPXRoaXMucGFyc2VYbWxTdHJpbmcoYSk7cmV0dXJuIHRoaXMueG1sMmpzb24oYil9LHRoaXMuanNvbjJ4bWxfc3RyPWZ1bmN0aW9uKGEpe3JldHVybiByKGEpfSx0aGlzLmpzb24yeG1sPWZ1bmN0aW9uKGEpe3ZhciBiPXRoaXMuanNvbjJ4bWxfc3RyKGEpO3JldHVybiB0aGlzLnBhcnNlWG1sU3RyaW5nKGIpfSx0aGlzLmdldFZlcnNpb249ZnVuY3Rpb24oKXtyZXR1cm4gc30sdGhpcy5lc2NhcGVNb2RlPWZ1bmN0aW9uKGEpe3Q9YX19ZnVuY3Rpb24gT2JqZWN0SXJvbihhKXt2YXIgYjtmb3IoYj1bXSxpPTAsbGVuPWEubGVuZ3RoO2xlbj5pO2krPTEpYVtpXS5pc1Jvb3Q/Yi5wdXNoKFwicm9vdFwiKTpiLnB1c2goYVtpXS5uYW1lKTt2YXIgYz1mdW5jdGlvbihhLGIpe3ZhciBjO2lmKG51bGwhPT1hJiZudWxsIT09Yilmb3IoYyBpbiBhKWEuaGFzT3duUHJvcGVydHkoYykmJihiLmhhc093blByb3BlcnR5KGMpfHwoYltjXT1hW2NdKSl9LGQ9ZnVuY3Rpb24oYSxiLGQpe3ZhciBlLGYsZyxoLGk7aWYobnVsbCE9PWEmJjAhPT1hLmxlbmd0aClmb3IoZT0wLGY9YS5sZW5ndGg7Zj5lO2UrPTEpZz1hW2VdLGIuaGFzT3duUHJvcGVydHkoZy5uYW1lKSYmKGQuaGFzT3duUHJvcGVydHkoZy5uYW1lKT9nLm1lcmdlJiYoaD1iW2cubmFtZV0saT1kW2cubmFtZV0sXCJvYmplY3RcIj09dHlwZW9mIGgmJlwib2JqZWN0XCI9PXR5cGVvZiBpP2MoaCxpKTpkW2cubmFtZV09bnVsbCE9Zy5tZXJnZUZ1bmN0aW9uP2cubWVyZ2VGdW5jdGlvbihoLGkpOmgraSk6ZFtnLm5hbWVdPWJbZy5uYW1lXSl9LGU9ZnVuY3Rpb24oYSxiKXt2YXIgYyxmLGcsaCxpLGosayxsPWE7aWYobnVsbCE9PWwuY2hpbGRyZW4mJjAhPT1sLmNoaWxkcmVuLmxlbmd0aClmb3IoYz0wLGY9bC5jaGlsZHJlbi5sZW5ndGg7Zj5jO2MrPTEpaWYoaj1sLmNoaWxkcmVuW2NdLGIuaGFzT3duUHJvcGVydHkoai5uYW1lKSlpZihqLmlzQXJyYXkpZm9yKGk9YltqLm5hbWUrXCJfYXNBcnJheVwiXSxnPTAsaD1pLmxlbmd0aDtoPmc7Zys9MSlrPWlbZ10sZChsLnByb3BlcnRpZXMsYixrKSxlKGosayk7ZWxzZSBrPWJbai5uYW1lXSxkKGwucHJvcGVydGllcyxiLGspLGUoaixrKX0sZj1mdW5jdGlvbihjKXt2YXIgZCxnLGgsaSxqLGssbDtpZihudWxsPT09YylyZXR1cm4gYztpZihcIm9iamVjdFwiIT10eXBlb2YgYylyZXR1cm4gYztmb3IoZD0wLGc9Yi5sZW5ndGg7Zz5kO2QrPTEpXCJyb290XCI9PT1iW2RdJiYoaj1hW2RdLGs9YyxlKGosaykpO2ZvcihpIGluIGMpaWYoYy5oYXNPd25Qcm9wZXJ0eShpKSl7aWYoaD1iLmluZGV4T2YoaSksLTEhPT1oKWlmKGo9YVtoXSxqLmlzQXJyYXkpZm9yKGw9Y1tpK1wiX2FzQXJyYXlcIl0sZD0wLGc9bC5sZW5ndGg7Zz5kO2QrPTEpaz1sW2RdLGUoaixrKTtlbHNlIGs9Y1tpXSxlKGosayk7ZihjW2ldKX1yZXR1cm4gY307cmV0dXJue3J1bjpmfX1pZihmdW5jdGlvbihhKXthKHZvaWQgMCxRPXt9KX0oZnVuY3Rpb24oYSxiKXtmdW5jdGlvbiBjKGEsYil7Yi5zdGFjayYmXCJvYmplY3RcIj09dHlwZW9mIGEmJm51bGwhPT1hJiZhLnN0YWNrJiYtMT09PWEuc3RhY2suaW5kZXhPZihOKSYmKGEuc3RhY2s9ZChhLnN0YWNrKStcIlxcblwiK04rXCJcXG5cIitkKGIuc3RhY2spKX1mdW5jdGlvbiBkKGEpe2Zvcih2YXIgYT1hLnNwbGl0KFwiXFxuXCIpLGI9W10sYz0wO2M8YS5sZW5ndGg7KytjKXt2YXIgZCxlPWFbY107aWYoZD0vYXQgLisgXFwoKC4qKTooXFxkKyk6XFxkK1xcKS8uZXhlYyhlKSl7dmFyIGY9ZFsyXTtkPWRbMV09PT13JiZmPj14JiZUPj1mfWVsc2UgZD0hMTshZCYmISgtMSE9PWUuaW5kZXhPZihcIihtb2R1bGUuanM6XCIpfHwtMSE9PWUuaW5kZXhPZihcIihub2RlLmpzOlwiKSkmJmIucHVzaChlKX1yZXR1cm4gYi5qb2luKFwiXFxuXCIpfWZ1bmN0aW9uIGUoKXtpZihFcnJvci5jYXB0dXJlU3RhY2tUcmFjZSl7dmFyIGEsYixjPUVycm9yLnByZXBhcmVTdGFja1RyYWNlO3JldHVybiBFcnJvci5wcmVwYXJlU3RhY2tUcmFjZT1mdW5jdGlvbihjLGQpe2E9ZFsxXS5nZXRGaWxlTmFtZSgpLGI9ZFsxXS5nZXRMaW5lTnVtYmVyKCl9LEVycm9yKCkuc3RhY2ssRXJyb3IucHJlcGFyZVN0YWNrVHJhY2U9Yyx3PWEsYn19ZnVuY3Rpb24gZihhLGIsYyl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuXCJ1bmRlZmluZWRcIiE9dHlwZW9mIGNvbnNvbGUmJlwiZnVuY3Rpb25cIj09dHlwZW9mIGNvbnNvbGUud2FybiYmY29uc29sZS53YXJuKGIrXCIgaXMgZGVwcmVjYXRlZCwgdXNlIFwiK2MrXCIgaW5zdGVhZC5cIixFcnJvcihcIlwiKS5zdGFjayksYS5hcHBseShhLGFyZ3VtZW50cyl9fWZ1bmN0aW9uIGcoKXtmdW5jdGlvbiBhKGEpe2MmJihiPW4oYSksSChjLGZ1bmN0aW9uKGEsYyl7QShmdW5jdGlvbigpe2IucHJvbWlzZURpc3BhdGNoLmFwcGx5KGIsYyl9KX0sdm9pZCAwKSxkPWM9dm9pZCAwKX12YXIgYixjPVtdLGQ9W10sZT1LKGcucHJvdG90eXBlKSxmPUsoaC5wcm90b3R5cGUpO3JldHVybiBmLnByb21pc2VEaXNwYXRjaD1mdW5jdGlvbihhLGUsZil7dmFyIGc9Ryhhcmd1bWVudHMpO2M/KGMucHVzaChnKSxcIndoZW5cIj09PWUmJmZbMV0mJmQucHVzaChmWzFdKSk6QShmdW5jdGlvbigpe2IucHJvbWlzZURpc3BhdGNoLmFwcGx5KGIsZyl9KX0sZi52YWx1ZU9mPWZ1bmN0aW9uKCl7cmV0dXJuIGM/ZjpiLnZhbHVlT2YoKX0sRXJyb3IuY2FwdHVyZVN0YWNrVHJhY2UmJihFcnJvci5jYXB0dXJlU3RhY2tUcmFjZShmLGcpLGYuc3RhY2s9Zi5zdGFjay5zdWJzdHJpbmcoZi5zdGFjay5pbmRleE9mKFwiXFxuXCIpKzEpKSx6KGYpLGUucHJvbWlzZT1mLGUucmVzb2x2ZT1hLGUucmVqZWN0PWZ1bmN0aW9uKGIpe2EobShiKSl9LGUubm90aWZ5PWZ1bmN0aW9uKGEpe2MmJkgoZCxmdW5jdGlvbihiLGMpe0EoZnVuY3Rpb24oKXtjKGEpfSl9LHZvaWQgMCl9LGV9ZnVuY3Rpb24gaChhLGIsYyxkKXt2b2lkIDA9PT1iJiYoYj1mdW5jdGlvbihhKXtyZXR1cm4gbShFcnJvcihcIlByb21pc2UgZG9lcyBub3Qgc3VwcG9ydCBvcGVyYXRpb246IFwiK2EpKX0pO3ZhciBlPUsoaC5wcm90b3R5cGUpO3JldHVybiBlLnByb21pc2VEaXNwYXRjaD1mdW5jdGlvbihjLGQsZil7dmFyIGc7dHJ5e2c9YVtkXT9hW2RdLmFwcGx5KGUsZik6Yi5jYWxsKGUsZCxmKX1jYXRjaChoKXtnPW0oaCl9YyYmYyhnKX0sYyYmKGUudmFsdWVPZj1jKSxkJiYoZS5leGNlcHRpb249ZCkseihlKSxlfWZ1bmN0aW9uIGkoYSl7cmV0dXJuIGooYSk/YS52YWx1ZU9mKCk6YX1mdW5jdGlvbiBqKGEpe3JldHVybiBhJiZcImZ1bmN0aW9uXCI9PXR5cGVvZiBhLnByb21pc2VEaXNwYXRjaH1mdW5jdGlvbiBrKGEpe3JldHVybiFqKGkoYSkpfWZ1bmN0aW9uIGwoYSl7cmV0dXJuIGE9aShhKSxqKGEpJiZcImV4Y2VwdGlvblwiaW4gYX1mdW5jdGlvbiBtKGEpe3ZhciBhPWF8fEVycm9yKCksYj1oKHt3aGVuOmZ1bmN0aW9uKGIpe2lmKGIpe3ZhciBjPUkoUCx0aGlzKTstMSE9PWMmJihRLnNwbGljZShjLDEpLFAuc3BsaWNlKGMsMSkpfXJldHVybiBiP2IoYSk6bShhKX19LGZ1bmN0aW9uKCl7cmV0dXJuIG0oYSl9LGZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LGEpO3JldHVybiFPJiZcInVuZGVmaW5lZFwiIT10eXBlb2Ygd2luZG93JiYhd2luZG93LlRvdWNoJiZ3aW5kb3cuY29uc29sZSYmY29uc29sZS5sb2coXCJTaG91bGQgYmUgZW1wdHk6XCIsUSksTz0hMCxQLnB1c2goYiksUS5wdXNoKGEpLGJ9ZnVuY3Rpb24gbihhKXtpZihqKGEpKXJldHVybiBhO2lmKChhPWkoYSkpJiZcImZ1bmN0aW9uXCI9PXR5cGVvZiBhLnRoZW4pe3ZhciBiPWcoKTtyZXR1cm4gYS50aGVuKGIucmVzb2x2ZSxiLnJlamVjdCxiLm5vdGlmeSksYi5wcm9taXNlfXJldHVybiBoKHt3aGVuOmZ1bmN0aW9uKCl7cmV0dXJuIGF9LGdldDpmdW5jdGlvbihiKXtyZXR1cm4gYVtiXX0scHV0OmZ1bmN0aW9uKGIsYyl7cmV0dXJuIGFbYl09YyxhfSxkZWw6ZnVuY3Rpb24oYil7cmV0dXJuIGRlbGV0ZSBhW2JdLGF9LHBvc3Q6ZnVuY3Rpb24oYixjKXtyZXR1cm4gYVtiXS5hcHBseShhLGMpfSxhcHBseTpmdW5jdGlvbihiKXtyZXR1cm4gYS5hcHBseSh2b2lkIDAsYil9LGtleXM6ZnVuY3Rpb24oKXtyZXR1cm4gTChhKX19LHZvaWQgMCxmdW5jdGlvbigpe3JldHVybiBhfSl9ZnVuY3Rpb24gbyhhLGIsZCxlKXtmdW5jdGlvbiBmKGEpe3RyeXtyZXR1cm4gYj9iKGEpOmF9Y2F0Y2goYyl7cmV0dXJuIG0oYyl9fWZ1bmN0aW9uIGgoYSl7aWYoZCl7YyhhLGspO3RyeXtyZXR1cm4gZChhKX1jYXRjaChiKXtyZXR1cm4gbShiKX19cmV0dXJuIG0oYSl9dmFyIGk9ZygpLGo9ITEsaz1uKGEpO3JldHVybiBBKGZ1bmN0aW9uKCl7ay5wcm9taXNlRGlzcGF0Y2goZnVuY3Rpb24oYSl7anx8KGo9ITAsaS5yZXNvbHZlKGYoYSkpKX0sXCJ3aGVuXCIsW2Z1bmN0aW9uKGEpe2p8fChqPSEwLGkucmVzb2x2ZShoKGEpKSl9XSl9KSxrLnByb21pc2VEaXNwYXRjaCh2b2lkIDAsXCJ3aGVuXCIsW3ZvaWQgMCxmdW5jdGlvbihhKXtpLm5vdGlmeShlP2UoYSk6YSl9XSksaS5wcm9taXNlfWZ1bmN0aW9uIHAoYSxiLGMpe3JldHVybiBvKGEsZnVuY3Rpb24oYSl7cmV0dXJuIHQoYSkudGhlbihmdW5jdGlvbihhKXtyZXR1cm4gYi5hcHBseSh2b2lkIDAsYSl9LGMpfSxjKX1mdW5jdGlvbiBxKGEsYixjKXt2YXIgZD1nKCk7cmV0dXJuIEEoZnVuY3Rpb24oKXtuKGEpLnByb21pc2VEaXNwYXRjaChkLnJlc29sdmUsYixjKX0pLGQucHJvbWlzZX1mdW5jdGlvbiByKGEpe3JldHVybiBmdW5jdGlvbihiKXt2YXIgYz1HKGFyZ3VtZW50cywxKTtyZXR1cm4gcShiLGEsYyl9fWZ1bmN0aW9uIHMoYSl7dmFyIGI9Ryhhcmd1bWVudHMsMSk7cmV0dXJuIFMoYSxiKX1mdW5jdGlvbiB0KGEpe3JldHVybiBvKGEsZnVuY3Rpb24oYSl7dmFyIGI9YS5sZW5ndGg7aWYoMD09PWIpcmV0dXJuIG4oYSk7dmFyIGM9ZygpO3JldHVybiBIKGEsZnVuY3Rpb24oZCxlLGYpe2soZSk/KGFbZl09aShlKSwwPT09LS1iJiZjLnJlc29sdmUoYSkpOm8oZSxmdW5jdGlvbihkKXthW2ZdPWQsMD09PS0tYiYmYy5yZXNvbHZlKGEpfSkuZmFpbChjLnJlamVjdCl9LHZvaWQgMCksYy5wcm9taXNlfSl9ZnVuY3Rpb24gdShhLGIpe3JldHVybiBvKGEsdm9pZCAwLGIpfWZ1bmN0aW9uIHYoYSxiKXt2YXIgYz1HKGFyZ3VtZW50cywyKSxkPWcoKTtyZXR1cm4gYy5wdXNoKGQubWFrZU5vZGVSZXNvbHZlcigpKSxSKGEsYixjKS5mYWlsKGQucmVqZWN0KSxkLnByb21pc2V9dmFyIHcseD1lKCkseT1mdW5jdGlvbigpe30sej1PYmplY3QuZnJlZXplfHx5O1widW5kZWZpbmVkXCIhPXR5cGVvZiBjYWphVk0mJih6PWNhamFWTS5kZWYpO3ZhciBBO2lmKFwidW5kZWZpbmVkXCIhPXR5cGVvZiBwcm9jZXNzKUE9cHJvY2Vzcy5uZXh0VGljaztlbHNlIGlmKFwiZnVuY3Rpb25cIj09dHlwZW9mIHNldEltbWVkaWF0ZSlBPXNldEltbWVkaWF0ZTtlbHNlIGlmKFwidW5kZWZpbmVkXCIhPXR5cGVvZiBNZXNzYWdlQ2hhbm5lbCl7dmFyIEI9bmV3IE1lc3NhZ2VDaGFubmVsLEM9e30sRD1DO0IucG9ydDEub25tZXNzYWdlPWZ1bmN0aW9uKCl7Qz1DLm5leHQ7dmFyIGE9Qy50YXNrO2RlbGV0ZSBDLnRhc2ssYSgpfSxBPWZ1bmN0aW9uKGEpe0Q9RC5uZXh0PXt0YXNrOmF9LEIucG9ydDIucG9zdE1lc3NhZ2UoMCl9fWVsc2UgQT1mdW5jdGlvbihhKXtzZXRUaW1lb3V0KGEsMCl9O3ZhciBFO0Z1bmN0aW9uLnByb3RvdHlwZS5iaW5kPyhFPUZ1bmN0aW9uLnByb3RvdHlwZS5iaW5kLEU9RS5iaW5kKEUuY2FsbCkpOkU9ZnVuY3Rpb24oYSl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIGEuY2FsbC5hcHBseShhLGFyZ3VtZW50cyl9fTt2YXIgRixHPUUoQXJyYXkucHJvdG90eXBlLnNsaWNlKSxIPUUoQXJyYXkucHJvdG90eXBlLnJlZHVjZXx8ZnVuY3Rpb24oYSxiKXt2YXIgYz0wLGQ9dGhpcy5sZW5ndGg7aWYoMT09PWFyZ3VtZW50cy5sZW5ndGgpZm9yKDs7KXtpZihjIGluIHRoaXMpe2I9dGhpc1tjKytdO2JyZWFrfWlmKCsrYz49ZCl0aHJvdyBuZXcgVHlwZUVycm9yfWZvcig7ZD5jO2MrKyljIGluIHRoaXMmJihiPWEoYix0aGlzW2NdLGMpKTtyZXR1cm4gYn0pLEk9RShBcnJheS5wcm90b3R5cGUuaW5kZXhPZnx8ZnVuY3Rpb24oYSl7Zm9yKHZhciBiPTA7Yjx0aGlzLmxlbmd0aDtiKyspaWYodGhpc1tiXT09PWEpcmV0dXJuIGI7cmV0dXJuLTF9KSxKPUUoQXJyYXkucHJvdG90eXBlLm1hcHx8ZnVuY3Rpb24oYSxiKXt2YXIgYz10aGlzLGQ9W107cmV0dXJuIEgoYyxmdW5jdGlvbihlLGYsZyl7ZC5wdXNoKGEuY2FsbChiLGYsZyxjKSl9LHZvaWQgMCksZH0pLEs9T2JqZWN0LmNyZWF0ZXx8ZnVuY3Rpb24oYSl7ZnVuY3Rpb24gYigpe31yZXR1cm4gYi5wcm90b3R5cGU9YSxuZXcgYn0sTD1PYmplY3Qua2V5c3x8ZnVuY3Rpb24oYSl7dmFyIGIsYz1bXTtmb3IoYiBpbiBhKWMucHVzaChiKTtyZXR1cm4gY30sTT1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nO0Y9XCJ1bmRlZmluZWRcIiE9dHlwZW9mIFJldHVyblZhbHVlP1JldHVyblZhbHVlOmZ1bmN0aW9uKGEpe3RoaXMudmFsdWU9YX07dmFyIE49XCJGcm9tIHByZXZpb3VzIGV2ZW50OlwiO2IubmV4dFRpY2s9QSxiLmRlZmVyPWcsZy5wcm90b3R5cGUubWFrZU5vZGVSZXNvbHZlcj1mdW5jdGlvbigpe3ZhciBhPXRoaXM7cmV0dXJuIGZ1bmN0aW9uKGIsYyl7Yj9hLnJlamVjdChiKTphcmd1bWVudHMubGVuZ3RoPjI/YS5yZXNvbHZlKEcoYXJndW1lbnRzLDEpKTphLnJlc29sdmUoYyl9fSxiLnByb21pc2U9ZnVuY3Rpb24oYSl7dmFyIGI9ZygpO3JldHVybiBzKGEsYi5yZXNvbHZlLGIucmVqZWN0LGIubm90aWZ5KS5mYWlsKGIucmVqZWN0KSxiLnByb21pc2V9LGIubWFrZVByb21pc2U9aCxoLnByb3RvdHlwZS50aGVuPWZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gbyh0aGlzLGEsYixjKX0saC5wcm90b3R5cGUudGhlblJlc29sdmU9ZnVuY3Rpb24oYSl7cmV0dXJuIG8odGhpcyxmdW5jdGlvbigpe3JldHVybiBhfSl9LEgoXCJpc1Jlc29sdmVkIGlzRnVsZmlsbGVkIGlzUmVqZWN0ZWQgZGlzcGF0Y2ggd2hlbiBzcHJlYWQgZ2V0IHB1dCBkZWwgcG9zdCBzZW5kIGludm9rZSBrZXlzIGZhcHBseSBmY2FsbCBmYmluZCBhbGwgYWxsUmVzb2x2ZWQgdGltZW91dCBkZWxheSBjYXRjaCBmaW5hbGx5IGZhaWwgZmluIHByb2dyZXNzIGVuZCBkb25lIG5mY2FsbCBuZmFwcGx5IG5mYmluZCBuY2FsbCBuYXBwbHkgbmJpbmQgbnBvc3QgbnNlbmQgbmludm9rZSBuZW5kIG5vZGVpZnlcIi5zcGxpdChcIiBcIiksZnVuY3Rpb24oYSxjKXtoLnByb3RvdHlwZVtjXT1mdW5jdGlvbigpe3JldHVybiBiW2NdLmFwcGx5KGIsW3RoaXNdLmNvbmNhdChHKGFyZ3VtZW50cykpKX19LHZvaWQgMCksaC5wcm90b3R5cGUudG9Tb3VyY2U9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy50b1N0cmluZygpfSxoLnByb3RvdHlwZS50b1N0cmluZz1mdW5jdGlvbigpe3JldHVyblwiW29iamVjdCBQcm9taXNlXVwifSx6KGgucHJvdG90eXBlKSxiLm5lYXJlcj1pLGIuaXNQcm9taXNlPWosYi5pc1Jlc29sdmVkPWZ1bmN0aW9uKGEpe3JldHVybiBrKGEpfHxsKGEpfSxiLmlzRnVsZmlsbGVkPWssYi5pc1JlamVjdGVkPWw7dmFyIE8sUD1bXSxRPVtdO2IucmVqZWN0PW0sYi5yZXNvbHZlPW4sYi5tYXN0ZXI9ZnVuY3Rpb24oYSl7cmV0dXJuIGgoe2lzRGVmOmZ1bmN0aW9uKCl7fX0sZnVuY3Rpb24oYixjKXtyZXR1cm4gcShhLGIsYyl9LGZ1bmN0aW9uKCl7cmV0dXJuIGkoYSl9KX0sYi53aGVuPW8sYi5zcHJlYWQ9cCxiLmFzeW5jPWZ1bmN0aW9uKGEpe3JldHVybiBmdW5jdGlvbigpe2Z1bmN0aW9uIGIoYSxiKXt2YXIgZjt0cnl7Zj1jW2FdKGIpfWNhdGNoKGcpe3JldHVyblwiW29iamVjdCBTdG9wSXRlcmF0aW9uXVwiPT09TShnKXx8ZyBpbnN0YW5jZW9mIEY/Zy52YWx1ZTptKGcpfXJldHVybiBvKGYsZCxlKX12YXIgYz1hLmFwcGx5KHRoaXMsYXJndW1lbnRzKSxkPWIuYmluZChiLFwic2VuZFwiKSxlPWIuYmluZChiLFwidGhyb3dcIik7cmV0dXJuIGQoKX19LGJbXCJyZXR1cm5cIl09ZnVuY3Rpb24oYSl7dGhyb3cgbmV3IEYoYSl9LGIucHJvbWlzZWQ9ZnVuY3Rpb24oYSl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIHAoW3RoaXMsdChhcmd1bWVudHMpXSxmdW5jdGlvbihiLGMpe3JldHVybiBhLmFwcGx5KGIsYyl9KX19LGIuZGlzcGF0Y2g9cSxiLmRpc3BhdGNoZXI9cixiLmdldD1yKFwiZ2V0XCIpLGIucHV0PXIoXCJwdXRcIiksYltcImRlbGV0ZVwiXT1iLmRlbD1yKFwiZGVsXCIpO3ZhciBSPWIucG9zdD1yKFwicG9zdFwiKTtiLnNlbmQ9ZnVuY3Rpb24oYSxiKXt2YXIgYz1HKGFyZ3VtZW50cywyKTtyZXR1cm4gUihhLGIsYyl9LGIuaW52b2tlPWYoYi5zZW5kLFwiaW52b2tlXCIsXCJzZW5kXCIpO3ZhciBTPWIuZmFwcGx5PXIoXCJhcHBseVwiKTtiW1widHJ5XCJdPXMsYi5mY2FsbD1zLGIuZmJpbmQ9ZnVuY3Rpb24oYSl7dmFyIGI9Ryhhcmd1bWVudHMsMSk7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIGM9Yi5jb25jYXQoRyhhcmd1bWVudHMpKTtyZXR1cm4gUyhhLGMpfX0sYi5rZXlzPXIoXCJrZXlzXCIpLGIuYWxsPXQsYi5hbGxSZXNvbHZlZD1mdW5jdGlvbihhKXtyZXR1cm4gbyhhLGZ1bmN0aW9uKGEpe3JldHVybiBvKHQoSihhLGZ1bmN0aW9uKGEpe3JldHVybiBvKGEseSx5KX0pKSxmdW5jdGlvbigpe3JldHVybiBKKGEsbil9KX0pfSxiW1wiY2F0Y2hcIl09Yi5mYWlsPXUsYi5wcm9ncmVzcz1mdW5jdGlvbihhLGIpe3JldHVybiBvKGEsdm9pZCAwLHZvaWQgMCxiKX0sYltcImZpbmFsbHlcIl09Yi5maW49ZnVuY3Rpb24oYSxiKXtyZXR1cm4gbyhhLGZ1bmN0aW9uKGEpe3JldHVybiBvKGIoKSxmdW5jdGlvbigpe3JldHVybiBhfSl9LGZ1bmN0aW9uKGEpe3JldHVybiBvKGIoKSxmdW5jdGlvbigpe3JldHVybiBtKGEpfSl9KX0sYi5kb25lPWZ1bmN0aW9uKGEsZCxlLGYpe2Q9ZHx8ZXx8Zj9vKGEsZCxlLGYpOmEsdShkLGZ1bmN0aW9uKGQpe0EoZnVuY3Rpb24oKXtpZihjKGQsYSksIWIub25lcnJvcil0aHJvdyBkO2Iub25lcnJvcihkKX0pfSl9LGIudGltZW91dD1mdW5jdGlvbihhLGIpe3ZhciBjPWcoKSxkPXNldFRpbWVvdXQoZnVuY3Rpb24oKXtjLnJlamVjdChFcnJvcihcIlRpbWVkIG91dCBhZnRlciBcIitiK1wiIG1zXCIpKX0sYik7cmV0dXJuIG8oYSxmdW5jdGlvbihhKXtjbGVhclRpbWVvdXQoZCksYy5yZXNvbHZlKGEpfSxmdW5jdGlvbihhKXtjbGVhclRpbWVvdXQoZCksYy5yZWplY3QoYSl9KSxjLnByb21pc2V9LGIuZGVsYXk9ZnVuY3Rpb24oYSxiKXt2b2lkIDA9PT1iJiYoYj1hLGE9dm9pZCAwKTt2YXIgYz1nKCk7cmV0dXJuIHNldFRpbWVvdXQoZnVuY3Rpb24oKXtjLnJlc29sdmUoYSl9LGIpLGMucHJvbWlzZX0sYi5uZmFwcGx5PWZ1bmN0aW9uKGEsYil7dmFyIGM9RyhiKSxkPWcoKTtyZXR1cm4gYy5wdXNoKGQubWFrZU5vZGVSZXNvbHZlcigpKSxTKGEsYykuZmFpbChkLnJlamVjdCksZC5wcm9taXNlfSxiLm5mY2FsbD1mdW5jdGlvbihhKXt2YXIgYj1HKGFyZ3VtZW50cywxKSxjPWcoKTtyZXR1cm4gYi5wdXNoKGMubWFrZU5vZGVSZXNvbHZlcigpKSxTKGEsYikuZmFpbChjLnJlamVjdCksYy5wcm9taXNlfSxiLm5mYmluZD1mdW5jdGlvbihhKXt2YXIgYj1HKGFyZ3VtZW50cywxKTtyZXR1cm4gZnVuY3Rpb24oKXt2YXIgYz1iLmNvbmNhdChHKGFyZ3VtZW50cykpLGQ9ZygpO3JldHVybiBjLnB1c2goZC5tYWtlTm9kZVJlc29sdmVyKCkpLFMoYSxjKS5mYWlsKGQucmVqZWN0KSxkLnByb21pc2V9fSxiLm5wb3N0PWZ1bmN0aW9uKGEsYixjKXt2YXIgYz1HKGMpLGQ9ZygpO3JldHVybiBjLnB1c2goZC5tYWtlTm9kZVJlc29sdmVyKCkpLFIoYSxiLGMpLmZhaWwoZC5yZWplY3QpLGQucHJvbWlzZX0sYi5uc2VuZD12LGIubmludm9rZT1mKHYsXCJuaW52b2tlXCIsXCJuc2VuZFwiKSxiLm5vZGVpZnk9ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYj8oYS50aGVuKGZ1bmN0aW9uKGEpe0EoZnVuY3Rpb24oKXtiKG51bGwsYSl9KX0sZnVuY3Rpb24oYSl7QShmdW5jdGlvbigpe2IoYSl9KX0pLHZvaWQgMCk6YX07dmFyIFQ9ZSgpfSksZnVuY3Rpb24oYSl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGI9e1ZFUlNJT046XCIwLjUuM1wifTtiLlN5c3RlbT1mdW5jdGlvbigpe3RoaXMuX21hcHBpbmdzPXt9LHRoaXMuX291dGxldHM9e30sdGhpcy5faGFuZGxlcnM9e30sdGhpcy5zdHJpY3RJbmplY3Rpb25zPSEwLHRoaXMuYXV0b01hcE91dGxldHM9ITEsdGhpcy5wb3N0SW5qZWN0aW9uSG9vaz1cInNldHVwXCJ9LGIuU3lzdGVtLnByb3RvdHlwZT17X2NyZWF0ZUFuZFNldHVwSW5zdGFuY2U6ZnVuY3Rpb24oYSxiKXt2YXIgYz1uZXcgYjtyZXR1cm4gdGhpcy5pbmplY3RJbnRvKGMsYSksY30sX3JldHJpZXZlRnJvbUNhY2hlT3JDcmVhdGU6ZnVuY3Rpb24oYSxiKXtcInVuZGVmaW5lZFwiPT10eXBlb2YgYiYmKGI9ITEpO3ZhciBjO2lmKCF0aGlzLl9tYXBwaW5ncy5oYXNPd25Qcm9wZXJ0eShhKSl0aHJvdyBuZXcgRXJyb3IoMWUzKTt2YXIgZD10aGlzLl9tYXBwaW5nc1thXTtyZXR1cm4hYiYmZC5pc1NpbmdsZXRvbj8obnVsbD09ZC5vYmplY3QmJihkLm9iamVjdD10aGlzLl9jcmVhdGVBbmRTZXR1cEluc3RhbmNlKGEsZC5jbGF6eikpLGM9ZC5vYmplY3QpOmM9ZC5jbGF6ej90aGlzLl9jcmVhdGVBbmRTZXR1cEluc3RhbmNlKGEsZC5jbGF6eik6ZC5vYmplY3QsY30sbWFwT3V0bGV0OmZ1bmN0aW9uKGEsYixjKXtpZihcInVuZGVmaW5lZFwiPT10eXBlb2YgYSl0aHJvdyBuZXcgRXJyb3IoMTAxMCk7cmV0dXJuIGI9Ynx8XCJnbG9iYWxcIixjPWN8fGEsdGhpcy5fb3V0bGV0cy5oYXNPd25Qcm9wZXJ0eShiKXx8KHRoaXMuX291dGxldHNbYl09e30pLHRoaXMuX291dGxldHNbYl1bY109YSx0aGlzfSxnZXRPYmplY3Q6ZnVuY3Rpb24oYSl7aWYoXCJ1bmRlZmluZWRcIj09dHlwZW9mIGEpdGhyb3cgbmV3IEVycm9yKDEwMjApO3JldHVybiB0aGlzLl9yZXRyaWV2ZUZyb21DYWNoZU9yQ3JlYXRlKGEpfSxtYXBWYWx1ZTpmdW5jdGlvbihhLGIpe2lmKFwidW5kZWZpbmVkXCI9PXR5cGVvZiBhKXRocm93IG5ldyBFcnJvcigxMDMwKTtyZXR1cm4gdGhpcy5fbWFwcGluZ3NbYV09e2NsYXp6Om51bGwsb2JqZWN0OmIsaXNTaW5nbGV0b246ITB9LHRoaXMuYXV0b01hcE91dGxldHMmJnRoaXMubWFwT3V0bGV0KGEpLHRoaXMuaGFzTWFwcGluZyhhKSYmdGhpcy5pbmplY3RJbnRvKGIsYSksdGhpc30saGFzTWFwcGluZzpmdW5jdGlvbihhKXtpZihcInVuZGVmaW5lZFwiPT10eXBlb2YgYSl0aHJvdyBuZXcgRXJyb3IoMTA0MCk7cmV0dXJuIHRoaXMuX21hcHBpbmdzLmhhc093blByb3BlcnR5KGEpfSxtYXBDbGFzczpmdW5jdGlvbihhLGIpe2lmKFwidW5kZWZpbmVkXCI9PXR5cGVvZiBhKXRocm93IG5ldyBFcnJvcigxMDUwKTtpZihcInVuZGVmaW5lZFwiPT10eXBlb2YgYil0aHJvdyBuZXcgRXJyb3IoMTA1MSk7cmV0dXJuIHRoaXMuX21hcHBpbmdzW2FdPXtjbGF6ejpiLG9iamVjdDpudWxsLGlzU2luZ2xldG9uOiExfSx0aGlzLmF1dG9NYXBPdXRsZXRzJiZ0aGlzLm1hcE91dGxldChhKSx0aGlzfSxtYXBTaW5nbGV0b246ZnVuY3Rpb24oYSxiKXtpZihcInVuZGVmaW5lZFwiPT10eXBlb2YgYSl0aHJvdyBuZXcgRXJyb3IoMTA2MCk7aWYoXCJ1bmRlZmluZWRcIj09dHlwZW9mIGIpdGhyb3cgbmV3IEVycm9yKDEwNjEpO3JldHVybiB0aGlzLl9tYXBwaW5nc1thXT17Y2xheno6YixvYmplY3Q6bnVsbCxpc1NpbmdsZXRvbjohMH0sdGhpcy5hdXRvTWFwT3V0bGV0cyYmdGhpcy5tYXBPdXRsZXQoYSksdGhpc30saW5zdGFudGlhdGU6ZnVuY3Rpb24oYSl7aWYoXCJ1bmRlZmluZWRcIj09dHlwZW9mIGEpdGhyb3cgbmV3IEVycm9yKDEwNzApO3JldHVybiB0aGlzLl9yZXRyaWV2ZUZyb21DYWNoZU9yQ3JlYXRlKGEsITApfSxpbmplY3RJbnRvOmZ1bmN0aW9uKGEsYil7aWYoXCJ1bmRlZmluZWRcIj09dHlwZW9mIGEpdGhyb3cgbmV3IEVycm9yKDEwODApO2lmKFwib2JqZWN0XCI9PXR5cGVvZiBhKXt2YXIgYz1bXTt0aGlzLl9vdXRsZXRzLmhhc093blByb3BlcnR5KFwiZ2xvYmFsXCIpJiZjLnB1c2godGhpcy5fb3V0bGV0cy5nbG9iYWwpLFwidW5kZWZpbmVkXCIhPXR5cGVvZiBiJiZ0aGlzLl9vdXRsZXRzLmhhc093blByb3BlcnR5KGIpJiZjLnB1c2godGhpcy5fb3V0bGV0c1tiXSk7Zm9yKHZhciBkIGluIGMpe3ZhciBlPWNbZF07Zm9yKHZhciBmIGluIGUpe3ZhciBnPWVbZl07KCF0aGlzLnN0cmljdEluamVjdGlvbnN8fGYgaW4gYSkmJihhW2ZdPXRoaXMuZ2V0T2JqZWN0KGcpKX19XCJzZXR1cFwiaW4gYSYmYS5zZXR1cC5jYWxsKGEpfXJldHVybiB0aGlzfSx1bm1hcDpmdW5jdGlvbihhKXtpZihcInVuZGVmaW5lZFwiPT10eXBlb2YgYSl0aHJvdyBuZXcgRXJyb3IoMTA5MCk7cmV0dXJuIGRlbGV0ZSB0aGlzLl9tYXBwaW5nc1thXSx0aGlzfSx1bm1hcE91dGxldDpmdW5jdGlvbihhLGIpe2lmKFwidW5kZWZpbmVkXCI9PXR5cGVvZiBhKXRocm93IG5ldyBFcnJvcigxMTAwKTtpZihcInVuZGVmaW5lZFwiPT10eXBlb2YgYil0aHJvdyBuZXcgRXJyb3IoMTEwMSk7cmV0dXJuIGRlbGV0ZSB0aGlzLl9vdXRsZXRzW2FdW2JdLHRoaXN9LG1hcEhhbmRsZXI6ZnVuY3Rpb24oYSxiLGMsZCxlKXtpZihcInVuZGVmaW5lZFwiPT10eXBlb2YgYSl0aHJvdyBuZXcgRXJyb3IoMTExMCk7cmV0dXJuIGI9Ynx8XCJnbG9iYWxcIixjPWN8fGEsXCJ1bmRlZmluZWRcIj09dHlwZW9mIGQmJihkPSExKSxcInVuZGVmaW5lZFwiPT10eXBlb2YgZSYmKGU9ITEpLHRoaXMuX2hhbmRsZXJzLmhhc093blByb3BlcnR5KGEpfHwodGhpcy5faGFuZGxlcnNbYV09e30pLHRoaXMuX2hhbmRsZXJzW2FdLmhhc093blByb3BlcnR5KGIpfHwodGhpcy5faGFuZGxlcnNbYV1bYl09W10pLHRoaXMuX2hhbmRsZXJzW2FdW2JdLnB1c2goe2hhbmRsZXI6YyxvbmVTaG90OmQscGFzc0V2ZW50OmV9KSx0aGlzfSx1bm1hcEhhbmRsZXI6ZnVuY3Rpb24oYSxiLGMpe2lmKFwidW5kZWZpbmVkXCI9PXR5cGVvZiBhKXRocm93IG5ldyBFcnJvcigxMTIwKTtpZihiPWJ8fFwiZ2xvYmFsXCIsYz1jfHxhLHRoaXMuX2hhbmRsZXJzLmhhc093blByb3BlcnR5KGEpJiZ0aGlzLl9oYW5kbGVyc1thXS5oYXNPd25Qcm9wZXJ0eShiKSl7dmFyIGQ9dGhpcy5faGFuZGxlcnNbYV1bYl07Zm9yKHZhciBlIGluIGQpe3ZhciBmPWRbZV07aWYoZi5oYW5kbGVyPT09Yyl7ZC5zcGxpY2UoZSwxKTticmVha319fXJldHVybiB0aGlzfSxub3RpZnk6ZnVuY3Rpb24oYSl7aWYoXCJ1bmRlZmluZWRcIj09dHlwZW9mIGEpdGhyb3cgbmV3IEVycm9yKDExMzApO3ZhciBiPUFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cyksYz1iLnNsaWNlKDEpO2lmKHRoaXMuX2hhbmRsZXJzLmhhc093blByb3BlcnR5KGEpKXt2YXIgZD10aGlzLl9oYW5kbGVyc1thXTtmb3IodmFyIGUgaW4gZCl7dmFyIGYsZz1kW2VdO1wiZ2xvYmFsXCIhPT1lJiYoZj10aGlzLmdldE9iamVjdChlKSk7dmFyIGgsaSxqPVtdO2ZvcihoPTAsaT1nLmxlbmd0aDtpPmg7aCsrKXt2YXIgayxsPWdbaF07az1mJiZcInN0cmluZ1wiPT10eXBlb2YgbC5oYW5kbGVyP2ZbbC5oYW5kbGVyXTpsLmhhbmRsZXIsbC5vbmVTaG90JiZqLnVuc2hpZnQoaCksbC5wYXNzRXZlbnQ/ay5hcHBseShmLGIpOmsuYXBwbHkoZixjKX1mb3IoaD0wLGk9ai5sZW5ndGg7aT5oO2grKylnLnNwbGljZShqW2hdLDEpfX1yZXR1cm4gdGhpc319LGEuZGlqb249Yn0odGhpcyksXCJ1bmRlZmluZWRcIj09dHlwZW9mIHV0aWxzKXZhciB1dGlscz17fTtcInVuZGVmaW5lZFwiPT10eXBlb2YgdXRpbHMuTWF0aCYmKHV0aWxzLk1hdGg9e30pLHV0aWxzLk1hdGgudG82NEJpdE51bWJlcj1mdW5jdGlvbihhLGIpe3ZhciBjLGQsZTtyZXR1cm4gYz1uZXcgZ29vZy5tYXRoLkxvbmcoMCxiKSxkPW5ldyBnb29nLm1hdGguTG9uZyhhLDApLGU9Yy5hZGQoZCksZS50b051bWJlcigpfSxnb29nPXt9LGdvb2cubWF0aD17fSxnb29nLm1hdGguTG9uZz1mdW5jdGlvbihhLGIpe3RoaXMubG93Xz0wfGEsdGhpcy5oaWdoXz0wfGJ9LGdvb2cubWF0aC5Mb25nLkludENhY2hlXz17fSxnb29nLm1hdGguTG9uZy5mcm9tSW50PWZ1bmN0aW9uKGEpe2lmKGE+PS0xMjgmJjEyOD5hKXt2YXIgYj1nb29nLm1hdGguTG9uZy5JbnRDYWNoZV9bYV07aWYoYilyZXR1cm4gYn12YXIgYz1uZXcgZ29vZy5tYXRoLkxvbmcoMHxhLDA+YT8tMTowKTtyZXR1cm4gYT49LTEyOCYmMTI4PmEmJihnb29nLm1hdGguTG9uZy5JbnRDYWNoZV9bYV09YyksY30sZ29vZy5tYXRoLkxvbmcuZnJvbU51bWJlcj1mdW5jdGlvbihhKXtyZXR1cm4gaXNOYU4oYSl8fCFpc0Zpbml0ZShhKT9nb29nLm1hdGguTG9uZy5aRVJPOmE8PS1nb29nLm1hdGguTG9uZy5UV09fUFdSXzYzX0RCTF8/Z29vZy5tYXRoLkxvbmcuTUlOX1ZBTFVFOmErMT49Z29vZy5tYXRoLkxvbmcuVFdPX1BXUl82M19EQkxfP2dvb2cubWF0aC5Mb25nLk1BWF9WQUxVRTowPmE/Z29vZy5tYXRoLkxvbmcuZnJvbU51bWJlcigtYSkubmVnYXRlKCk6bmV3IGdvb2cubWF0aC5Mb25nKDB8YSVnb29nLm1hdGguTG9uZy5UV09fUFdSXzMyX0RCTF8sMHxhL2dvb2cubWF0aC5Mb25nLlRXT19QV1JfMzJfREJMXyl9LGdvb2cubWF0aC5Mb25nLmZyb21CaXRzPWZ1bmN0aW9uKGEsYil7cmV0dXJuIG5ldyBnb29nLm1hdGguTG9uZyhhLGIpfSxnb29nLm1hdGguTG9uZy5mcm9tU3RyaW5nPWZ1bmN0aW9uKGEsYil7aWYoMD09YS5sZW5ndGgpdGhyb3cgRXJyb3IoXCJudW1iZXIgZm9ybWF0IGVycm9yOiBlbXB0eSBzdHJpbmdcIik7dmFyIGM9Ynx8MTA7aWYoMj5jfHxjPjM2KXRocm93IEVycm9yKFwicmFkaXggb3V0IG9mIHJhbmdlOiBcIitjKTtpZihcIi1cIj09YS5jaGFyQXQoMCkpcmV0dXJuIGdvb2cubWF0aC5Mb25nLmZyb21TdHJpbmcoYS5zdWJzdHJpbmcoMSksYykubmVnYXRlKCk7aWYoYS5pbmRleE9mKFwiLVwiKT49MCl0aHJvdyBFcnJvcignbnVtYmVyIGZvcm1hdCBlcnJvcjogaW50ZXJpb3IgXCItXCIgY2hhcmFjdGVyOiAnK2EpO2Zvcih2YXIgZD1nb29nLm1hdGguTG9uZy5mcm9tTnVtYmVyKE1hdGgucG93KGMsOCkpLGU9Z29vZy5tYXRoLkxvbmcuWkVSTyxmPTA7ZjxhLmxlbmd0aDtmKz04KXt2YXIgZz1NYXRoLm1pbig4LGEubGVuZ3RoLWYpLGg9cGFyc2VJbnQoYS5zdWJzdHJpbmcoZixmK2cpLGMpO2lmKDg+Zyl7dmFyIGk9Z29vZy5tYXRoLkxvbmcuZnJvbU51bWJlcihNYXRoLnBvdyhjLGcpKTtlPWUubXVsdGlwbHkoaSkuYWRkKGdvb2cubWF0aC5Mb25nLmZyb21OdW1iZXIoaCkpfWVsc2UgZT1lLm11bHRpcGx5KGQpLGU9ZS5hZGQoZ29vZy5tYXRoLkxvbmcuZnJvbU51bWJlcihoKSl9cmV0dXJuIGV9LGdvb2cubWF0aC5Mb25nLlRXT19QV1JfMTZfREJMXz02NTUzNixnb29nLm1hdGguTG9uZy5UV09fUFdSXzI0X0RCTF89MTw8MjQsZ29vZy5tYXRoLkxvbmcuVFdPX1BXUl8zMl9EQkxfPWdvb2cubWF0aC5Mb25nLlRXT19QV1JfMTZfREJMXypnb29nLm1hdGguTG9uZy5UV09fUFdSXzE2X0RCTF8sZ29vZy5tYXRoLkxvbmcuVFdPX1BXUl8zMV9EQkxfPWdvb2cubWF0aC5Mb25nLlRXT19QV1JfMzJfREJMXy8yLGdvb2cubWF0aC5Mb25nLlRXT19QV1JfNDhfREJMXz1nb29nLm1hdGguTG9uZy5UV09fUFdSXzMyX0RCTF8qZ29vZy5tYXRoLkxvbmcuVFdPX1BXUl8xNl9EQkxfLGdvb2cubWF0aC5Mb25nLlRXT19QV1JfNjRfREJMXz1nb29nLm1hdGguTG9uZy5UV09fUFdSXzMyX0RCTF8qZ29vZy5tYXRoLkxvbmcuVFdPX1BXUl8zMl9EQkxfLGdvb2cubWF0aC5Mb25nLlRXT19QV1JfNjNfREJMXz1nb29nLm1hdGguTG9uZy5UV09fUFdSXzY0X0RCTF8vMixnb29nLm1hdGguTG9uZy5aRVJPPWdvb2cubWF0aC5Mb25nLmZyb21JbnQoMCksZ29vZy5tYXRoLkxvbmcuT05FPWdvb2cubWF0aC5Mb25nLmZyb21JbnQoMSksZ29vZy5tYXRoLkxvbmcuTkVHX09ORT1nb29nLm1hdGguTG9uZy5mcm9tSW50KC0xKSxnb29nLm1hdGguTG9uZy5NQVhfVkFMVUU9Z29vZy5tYXRoLkxvbmcuZnJvbUJpdHMoLTEsMjE0NzQ4MzY0NyksZ29vZy5tYXRoLkxvbmcuTUlOX1ZBTFVFPWdvb2cubWF0aC5Mb25nLmZyb21CaXRzKDAsLTIxNDc0ODM2NDgpLGdvb2cubWF0aC5Mb25nLlRXT19QV1JfMjRfPWdvb2cubWF0aC5Mb25nLmZyb21JbnQoMTw8MjQpLGdvb2cubWF0aC5Mb25nLnByb3RvdHlwZS50b0ludD1mdW5jdGlvbigpe3JldHVybiB0aGlzLmxvd199LGdvb2cubWF0aC5Mb25nLnByb3RvdHlwZS50b051bWJlcj1mdW5jdGlvbigpe3JldHVybiB0aGlzLmhpZ2hfKmdvb2cubWF0aC5Mb25nLlRXT19QV1JfMzJfREJMXyt0aGlzLmdldExvd0JpdHNVbnNpZ25lZCgpfSxnb29nLm1hdGguTG9uZy5wcm90b3R5cGUudG9TdHJpbmc9ZnVuY3Rpb24oYSl7dmFyIGI9YXx8MTA7aWYoMj5ifHxiPjM2KXRocm93IEVycm9yKFwicmFkaXggb3V0IG9mIHJhbmdlOiBcIitiKTtpZih0aGlzLmlzWmVybygpKXJldHVyblwiMFwiO2lmKHRoaXMuaXNOZWdhdGl2ZSgpKXtpZih0aGlzLmVxdWFscyhnb29nLm1hdGguTG9uZy5NSU5fVkFMVUUpKXt2YXIgYz1nb29nLm1hdGguTG9uZy5mcm9tTnVtYmVyKGIpLGQ9dGhpcy5kaXYoYyksZT1kLm11bHRpcGx5KGMpLnN1YnRyYWN0KHRoaXMpO3JldHVybiBkLnRvU3RyaW5nKGIpK2UudG9JbnQoKS50b1N0cmluZyhiKX1yZXR1cm5cIi1cIit0aGlzLm5lZ2F0ZSgpLnRvU3RyaW5nKGIpfWZvcih2YXIgZj1nb29nLm1hdGguTG9uZy5mcm9tTnVtYmVyKE1hdGgucG93KGIsNikpLGU9dGhpcyxnPVwiXCI7Oyl7dmFyIGg9ZS5kaXYoZiksaT1lLnN1YnRyYWN0KGgubXVsdGlwbHkoZikpLnRvSW50KCksaj1pLnRvU3RyaW5nKGIpO2lmKGU9aCxlLmlzWmVybygpKXJldHVybiBqK2c7Zm9yKDtqLmxlbmd0aDw2OylqPVwiMFwiK2o7Zz1cIlwiK2orZ319LGdvb2cubWF0aC5Mb25nLnByb3RvdHlwZS5nZXRIaWdoQml0cz1mdW5jdGlvbigpe3JldHVybiB0aGlzLmhpZ2hffSxnb29nLm1hdGguTG9uZy5wcm90b3R5cGUuZ2V0TG93Qml0cz1mdW5jdGlvbigpe3JldHVybiB0aGlzLmxvd199LGdvb2cubWF0aC5Mb25nLnByb3RvdHlwZS5nZXRMb3dCaXRzVW5zaWduZWQ9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5sb3dfPj0wP3RoaXMubG93Xzpnb29nLm1hdGguTG9uZy5UV09fUFdSXzMyX0RCTF8rdGhpcy5sb3dffSxnb29nLm1hdGguTG9uZy5wcm90b3R5cGUuZ2V0TnVtQml0c0Ficz1mdW5jdGlvbigpe2lmKHRoaXMuaXNOZWdhdGl2ZSgpKXJldHVybiB0aGlzLmVxdWFscyhnb29nLm1hdGguTG9uZy5NSU5fVkFMVUUpPzY0OnRoaXMubmVnYXRlKCkuZ2V0TnVtQml0c0FicygpO2Zvcih2YXIgYT0wIT10aGlzLmhpZ2hfP3RoaXMuaGlnaF86dGhpcy5sb3dfLGI9MzE7Yj4wJiYwPT0oYSYxPDxiKTtiLS0pO3JldHVybiAwIT10aGlzLmhpZ2hfP2IrMzM6YisxfSxnb29nLm1hdGguTG9uZy5wcm90b3R5cGUuaXNaZXJvPWZ1bmN0aW9uKCl7cmV0dXJuIDA9PXRoaXMuaGlnaF8mJjA9PXRoaXMubG93X30sZ29vZy5tYXRoLkxvbmcucHJvdG90eXBlLmlzTmVnYXRpdmU9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5oaWdoXzwwfSxnb29nLm1hdGguTG9uZy5wcm90b3R5cGUuaXNPZGQ9ZnVuY3Rpb24oKXtyZXR1cm4gMT09KDEmdGhpcy5sb3dfKX0sZ29vZy5tYXRoLkxvbmcucHJvdG90eXBlLmVxdWFscz1mdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5oaWdoXz09YS5oaWdoXyYmdGhpcy5sb3dfPT1hLmxvd199LGdvb2cubWF0aC5Mb25nLnByb3RvdHlwZS5ub3RFcXVhbHM9ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuaGlnaF8hPWEuaGlnaF98fHRoaXMubG93XyE9YS5sb3dffSxnb29nLm1hdGguTG9uZy5wcm90b3R5cGUubGVzc1RoYW49ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuY29tcGFyZShhKTwwfSxnb29nLm1hdGguTG9uZy5wcm90b3R5cGUubGVzc1RoYW5PckVxdWFsPWZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmNvbXBhcmUoYSk8PTB9LGdvb2cubWF0aC5Mb25nLnByb3RvdHlwZS5ncmVhdGVyVGhhbj1mdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5jb21wYXJlKGEpPjB9LGdvb2cubWF0aC5Mb25nLnByb3RvdHlwZS5ncmVhdGVyVGhhbk9yRXF1YWw9ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuY29tcGFyZShhKT49MH0sZ29vZy5tYXRoLkxvbmcucHJvdG90eXBlLmNvbXBhcmU9ZnVuY3Rpb24oYSl7aWYodGhpcy5lcXVhbHMoYSkpcmV0dXJuIDA7dmFyIGI9dGhpcy5pc05lZ2F0aXZlKCksYz1hLmlzTmVnYXRpdmUoKTtyZXR1cm4gYiYmIWM/LTE6IWImJmM/MTp0aGlzLnN1YnRyYWN0KGEpLmlzTmVnYXRpdmUoKT8tMToxfSxnb29nLm1hdGguTG9uZy5wcm90b3R5cGUubmVnYXRlPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZXF1YWxzKGdvb2cubWF0aC5Mb25nLk1JTl9WQUxVRSk/Z29vZy5tYXRoLkxvbmcuTUlOX1ZBTFVFOnRoaXMubm90KCkuYWRkKGdvb2cubWF0aC5Mb25nLk9ORSl9LGdvb2cubWF0aC5Mb25nLnByb3RvdHlwZS5hZGQ9ZnVuY3Rpb24oYSl7dmFyIGI9dGhpcy5oaWdoXz4+PjE2LGM9NjU1MzUmdGhpcy5oaWdoXyxkPXRoaXMubG93Xz4+PjE2LGU9NjU1MzUmdGhpcy5sb3dfLGY9YS5oaWdoXz4+PjE2LGc9NjU1MzUmYS5oaWdoXyxoPWEubG93Xz4+PjE2LGk9NjU1MzUmYS5sb3dfLGo9MCxrPTAsbD0wLG09MDtyZXR1cm4gbSs9ZStpLGwrPW0+Pj4xNixtJj02NTUzNSxsKz1kK2gsays9bD4+PjE2LGwmPTY1NTM1LGsrPWMrZyxqKz1rPj4+MTYsayY9NjU1MzUsais9YitmLGomPTY1NTM1LGdvb2cubWF0aC5Mb25nLmZyb21CaXRzKGw8PDE2fG0sajw8MTZ8ayl9LGdvb2cubWF0aC5Mb25nLnByb3RvdHlwZS5zdWJ0cmFjdD1mdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hZGQoYS5uZWdhdGUoKSl9LGdvb2cubWF0aC5Mb25nLnByb3RvdHlwZS5tdWx0aXBseT1mdW5jdGlvbihhKXtpZih0aGlzLmlzWmVybygpKXJldHVybiBnb29nLm1hdGguTG9uZy5aRVJPO2lmKGEuaXNaZXJvKCkpcmV0dXJuIGdvb2cubWF0aC5Mb25nLlpFUk87aWYodGhpcy5lcXVhbHMoZ29vZy5tYXRoLkxvbmcuTUlOX1ZBTFVFKSlyZXR1cm4gYS5pc09kZCgpP2dvb2cubWF0aC5Mb25nLk1JTl9WQUxVRTpnb29nLm1hdGguTG9uZy5aRVJPO2lmKGEuZXF1YWxzKGdvb2cubWF0aC5Mb25nLk1JTl9WQUxVRSkpcmV0dXJuIHRoaXMuaXNPZGQoKT9nb29nLm1hdGguTG9uZy5NSU5fVkFMVUU6Z29vZy5tYXRoLkxvbmcuWkVSTztpZih0aGlzLmlzTmVnYXRpdmUoKSlyZXR1cm4gYS5pc05lZ2F0aXZlKCk/dGhpcy5uZWdhdGUoKS5tdWx0aXBseShhLm5lZ2F0ZSgpKTp0aGlzLm5lZ2F0ZSgpLm11bHRpcGx5KGEpLm5lZ2F0ZSgpO2lmKGEuaXNOZWdhdGl2ZSgpKXJldHVybiB0aGlzLm11bHRpcGx5KGEubmVnYXRlKCkpLm5lZ2F0ZSgpO2lmKHRoaXMubGVzc1RoYW4oZ29vZy5tYXRoLkxvbmcuVFdPX1BXUl8yNF8pJiZhLmxlc3NUaGFuKGdvb2cubWF0aC5Mb25nLlRXT19QV1JfMjRfKSlyZXR1cm4gZ29vZy5tYXRoLkxvbmcuZnJvbU51bWJlcih0aGlzLnRvTnVtYmVyKCkqYS50b051bWJlcigpKTt2YXIgYj10aGlzLmhpZ2hfPj4+MTYsYz02NTUzNSZ0aGlzLmhpZ2hfLGQ9dGhpcy5sb3dfPj4+MTYsZT02NTUzNSZ0aGlzLmxvd18sZj1hLmhpZ2hfPj4+MTYsZz02NTUzNSZhLmhpZ2hfLGg9YS5sb3dfPj4+MTYsaT02NTUzNSZhLmxvd18saj0wLGs9MCxsPTAsbT0wO3JldHVybiBtKz1lKmksbCs9bT4+PjE2LG0mPTY1NTM1LGwrPWQqaSxrKz1sPj4+MTYsbCY9NjU1MzUsbCs9ZSpoLGsrPWw+Pj4xNixsJj02NTUzNSxrKz1jKmksais9az4+PjE2LGsmPTY1NTM1LGsrPWQqaCxqKz1rPj4+MTYsayY9NjU1MzUsays9ZSpnLGorPWs+Pj4xNixrJj02NTUzNSxqKz1iKmkrYypoK2QqZytlKmYsaiY9NjU1MzUsZ29vZy5tYXRoLkxvbmcuZnJvbUJpdHMobDw8MTZ8bSxqPDwxNnxrKX0sZ29vZy5tYXRoLkxvbmcucHJvdG90eXBlLmRpdj1mdW5jdGlvbihhKXtpZihhLmlzWmVybygpKXRocm93IEVycm9yKFwiZGl2aXNpb24gYnkgemVyb1wiKTtpZih0aGlzLmlzWmVybygpKXJldHVybiBnb29nLm1hdGguTG9uZy5aRVJPO2lmKHRoaXMuZXF1YWxzKGdvb2cubWF0aC5Mb25nLk1JTl9WQUxVRSkpe2lmKGEuZXF1YWxzKGdvb2cubWF0aC5Mb25nLk9ORSl8fGEuZXF1YWxzKGdvb2cubWF0aC5Mb25nLk5FR19PTkUpKXJldHVybiBnb29nLm1hdGguTG9uZy5NSU5fVkFMVUU7aWYoYS5lcXVhbHMoZ29vZy5tYXRoLkxvbmcuTUlOX1ZBTFVFKSlyZXR1cm4gZ29vZy5tYXRoLkxvbmcuT05FO3ZhciBiPXRoaXMuc2hpZnRSaWdodCgxKSxjPWIuZGl2KGEpLnNoaWZ0TGVmdCgxKTtpZihjLmVxdWFscyhnb29nLm1hdGguTG9uZy5aRVJPKSlyZXR1cm4gYS5pc05lZ2F0aXZlKCk/Z29vZy5tYXRoLkxvbmcuT05FOmdvb2cubWF0aC5Mb25nLk5FR19PTkU7dmFyIGQ9dGhpcy5zdWJ0cmFjdChhLm11bHRpcGx5KGMpKSxlPWMuYWRkKGQuZGl2KGEpKTtyZXR1cm4gZX1pZihhLmVxdWFscyhnb29nLm1hdGguTG9uZy5NSU5fVkFMVUUpKXJldHVybiBnb29nLm1hdGguTG9uZy5aRVJPO2lmKHRoaXMuaXNOZWdhdGl2ZSgpKXJldHVybiBhLmlzTmVnYXRpdmUoKT90aGlzLm5lZ2F0ZSgpLmRpdihhLm5lZ2F0ZSgpKTp0aGlzLm5lZ2F0ZSgpLmRpdihhKS5uZWdhdGUoKTtpZihhLmlzTmVnYXRpdmUoKSlyZXR1cm4gdGhpcy5kaXYoYS5uZWdhdGUoKSkubmVnYXRlKCk7Zm9yKHZhciBmPWdvb2cubWF0aC5Mb25nLlpFUk8sZD10aGlzO2QuZ3JlYXRlclRoYW5PckVxdWFsKGEpOyl7Zm9yKHZhciBjPU1hdGgubWF4KDEsTWF0aC5mbG9vcihkLnRvTnVtYmVyKCkvYS50b051bWJlcigpKSksZz1NYXRoLmNlaWwoTWF0aC5sb2coYykvTWF0aC5MTjIpLGg9NDg+PWc/MTpNYXRoLnBvdygyLGctNDgpLGk9Z29vZy5tYXRoLkxvbmcuZnJvbU51bWJlcihjKSxqPWkubXVsdGlwbHkoYSk7ai5pc05lZ2F0aXZlKCl8fGouZ3JlYXRlclRoYW4oZCk7KWMtPWgsaT1nb29nLm1hdGguTG9uZy5mcm9tTnVtYmVyKGMpLGo9aS5tdWx0aXBseShhKTtpLmlzWmVybygpJiYoaT1nb29nLm1hdGguTG9uZy5PTkUpLGY9Zi5hZGQoaSksZD1kLnN1YnRyYWN0KGopfXJldHVybiBmfSxnb29nLm1hdGguTG9uZy5wcm90b3R5cGUubW9kdWxvPWZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLnN1YnRyYWN0KHRoaXMuZGl2KGEpLm11bHRpcGx5KGEpKX0sZ29vZy5tYXRoLkxvbmcucHJvdG90eXBlLm5vdD1mdW5jdGlvbigpe3JldHVybiBnb29nLm1hdGguTG9uZy5mcm9tQml0cyh+dGhpcy5sb3dfLH50aGlzLmhpZ2hfKX0sZ29vZy5tYXRoLkxvbmcucHJvdG90eXBlLmFuZD1mdW5jdGlvbihhKXtyZXR1cm4gZ29vZy5tYXRoLkxvbmcuZnJvbUJpdHModGhpcy5sb3dfJmEubG93Xyx0aGlzLmhpZ2hfJmEuaGlnaF8pfSxnb29nLm1hdGguTG9uZy5wcm90b3R5cGUub3I9ZnVuY3Rpb24oYSl7cmV0dXJuIGdvb2cubWF0aC5Mb25nLmZyb21CaXRzKHRoaXMubG93X3xhLmxvd18sdGhpcy5oaWdoX3xhLmhpZ2hfKX0sZ29vZy5tYXRoLkxvbmcucHJvdG90eXBlLnhvcj1mdW5jdGlvbihhKXtyZXR1cm4gZ29vZy5tYXRoLkxvbmcuZnJvbUJpdHModGhpcy5sb3dfXmEubG93Xyx0aGlzLmhpZ2hfXmEuaGlnaF8pfSxnb29nLm1hdGguTG9uZy5wcm90b3R5cGUuc2hpZnRMZWZ0PWZ1bmN0aW9uKGEpe2lmKGEmPTYzLDA9PWEpcmV0dXJuIHRoaXM7dmFyIGI9dGhpcy5sb3dfO2lmKDMyPmEpe3ZhciBjPXRoaXMuaGlnaF87cmV0dXJuIGdvb2cubWF0aC5Mb25nLmZyb21CaXRzKGI8PGEsYzw8YXxiPj4+MzItYSl9cmV0dXJuIGdvb2cubWF0aC5Mb25nLmZyb21CaXRzKDAsYjw8YS0zMil9LGdvb2cubWF0aC5Mb25nLnByb3RvdHlwZS5zaGlmdFJpZ2h0PWZ1bmN0aW9uKGEpe2lmKGEmPTYzLDA9PWEpcmV0dXJuIHRoaXM7dmFyIGI9dGhpcy5oaWdoXztpZigzMj5hKXt2YXIgYz10aGlzLmxvd187cmV0dXJuIGdvb2cubWF0aC5Mb25nLmZyb21CaXRzKGM+Pj5hfGI8PDMyLWEsYj4+YSl9cmV0dXJuIGdvb2cubWF0aC5Mb25nLmZyb21CaXRzKGI+PmEtMzIsYj49MD8wOi0xKX0sZ29vZy5tYXRoLkxvbmcucHJvdG90eXBlLnNoaWZ0UmlnaHRVbnNpZ25lZD1mdW5jdGlvbihhKXtpZihhJj02MywwPT1hKXJldHVybiB0aGlzO3ZhciBiPXRoaXMuaGlnaF87aWYoMzI+YSl7dmFyIGM9dGhpcy5sb3dfO3JldHVybiBnb29nLm1hdGguTG9uZy5mcm9tQml0cyhjPj4+YXxiPDwzMi1hLGI+Pj5hKX1yZXR1cm4gMzI9PWE/Z29vZy5tYXRoLkxvbmcuZnJvbUJpdHMoYiwwKTpnb29nLm1hdGguTG9uZy5mcm9tQml0cyhiPj4+YS0zMiwwKX07dmFyIFVURjg9e307VVRGOC5lbmNvZGU9ZnVuY3Rpb24oYSl7Zm9yKHZhciBiPVtdLGM9MDtjPGEubGVuZ3RoOysrYyl7dmFyIGQ9YS5jaGFyQ29kZUF0KGMpOzEyOD5kP2IucHVzaChkKToyMDQ4PmQ/KGIucHVzaCgxOTJ8ZD4+NiksYi5wdXNoKDEyOHw2MyZkKSk6NjU1MzY+ZD8oYi5wdXNoKDIyNHxkPj4xMiksYi5wdXNoKDEyOHw2MyZkPj42KSxiLnB1c2goMTI4fDYzJmQpKTooYi5wdXNoKDI0MHxkPj4xOCksYi5wdXNoKDEyOHw2MyZkPj4xMiksYi5wdXNoKDEyOHw2MyZkPj42KSxiLnB1c2goMTI4fDYzJmQpKX1yZXR1cm4gYn0sVVRGOC5kZWNvZGU9ZnVuY3Rpb24oYSl7Zm9yKHZhciBiPVtdLGM9MDtjPGEubGVuZ3RoOyl7dmFyIGQ9YVtjKytdOzEyOD5kfHwoMjI0PmQ/KGQ9KDMxJmQpPDw2LGR8PTYzJmFbYysrXSk6MjQwPmQ/KGQ9KDE1JmQpPDwxMixkfD0oNjMmYVtjKytdKTw8NixkfD02MyZhW2MrK10pOihkPSg3JmQpPDwxOCxkfD0oNjMmYVtjKytdKTw8MTIsZHw9KDYzJmFbYysrXSk8PDYsZHw9NjMmYVtjKytdKSksYi5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoZCkpfXJldHVybiBiLmpvaW4oXCJcIil9O3ZhciBCQVNFNjQ9e307aWYoZnVuY3Rpb24oYil7dmFyIGM9ZnVuY3Rpb24oYSl7Zm9yKHZhciBjPTAsZD1bXSxlPTB8YS5sZW5ndGgvMzswPGUtLTspe3ZhciBmPShhW2NdPDwxNikrKGFbYysxXTw8OCkrYVtjKzJdO2MrPTMsZC5wdXNoKGIuY2hhckF0KDYzJmY+PjE4KSksZC5wdXNoKGIuY2hhckF0KDYzJmY+PjEyKSksZC5wdXNoKGIuY2hhckF0KDYzJmY+PjYpKSxkLnB1c2goYi5jaGFyQXQoNjMmZikpfWlmKDI9PWEubGVuZ3RoLWMpe3ZhciBmPShhW2NdPDwxNikrKGFbYysxXTw8OCk7ZC5wdXNoKGIuY2hhckF0KDYzJmY+PjE4KSksZC5wdXNoKGIuY2hhckF0KDYzJmY+PjEyKSksZC5wdXNoKGIuY2hhckF0KDYzJmY+PjYpKSxkLnB1c2goXCI9XCIpfWVsc2UgaWYoMT09YS5sZW5ndGgtYyl7dmFyIGY9YVtjXTw8MTY7ZC5wdXNoKGIuY2hhckF0KDYzJmY+PjE4KSksZC5wdXNoKGIuY2hhckF0KDYzJmY+PjEyKSksZC5wdXNoKFwiPT1cIil9cmV0dXJuIGQuam9pbihcIlwiKX0sZD1mdW5jdGlvbigpe2Zvcih2YXIgYT1bXSxjPTA7YzxiLmxlbmd0aDsrK2MpYVtiLmNoYXJDb2RlQXQoYyldPWM7cmV0dXJuIGFbXCI9XCIuY2hhckNvZGVBdCgwKV09MCxhfSgpLGU9ZnVuY3Rpb24oYSl7Zm9yKHZhciBiPTAsYz1bXSxlPTB8YS5sZW5ndGgvNDswPGUtLTspe3ZhciBmPShkW2EuY2hhckNvZGVBdChiKV08PDE4KSsoZFthLmNoYXJDb2RlQXQoYisxKV08PDEyKSsoZFthLmNoYXJDb2RlQXQoYisyKV08PDYpK2RbYS5jaGFyQ29kZUF0KGIrMyldO2MucHVzaCgyNTUmZj4+MTYpLGMucHVzaCgyNTUmZj4+OCksYy5wdXNoKDI1NSZmKSxiKz00fXJldHVybiBjJiYoXCI9XCI9PWEuY2hhckF0KGItMik/KGMucG9wKCksYy5wb3AoKSk6XCI9XCI9PWEuY2hhckF0KGItMSkmJmMucG9wKCkpLGN9LGY9e307Zi5lbmNvZGU9ZnVuY3Rpb24oYSl7Zm9yKHZhciBiPVtdLGM9MDtjPGEubGVuZ3RoOysrYyliLnB1c2goYS5jaGFyQ29kZUF0KGMpKTtyZXR1cm4gYn0sZi5kZWNvZGU9ZnVuY3Rpb24oKXtmb3IodmFyIGI9MDtiPHMubGVuZ3RoOysrYilhW2JdPVN0cmluZy5mcm9tQ2hhckNvZGUoYVtiXSk7cmV0dXJuIGEuam9pbihcIlwiKX0sQkFTRTY0LmRlY29kZUFycmF5PWZ1bmN0aW9uKGEpe3ZhciBiPWUoYSk7cmV0dXJuIG5ldyBVaW50OEFycmF5KGIpfSxCQVNFNjQuZW5jb2RlQVNDSUk9ZnVuY3Rpb24oYSl7dmFyIGI9Zi5lbmNvZGUoYSk7cmV0dXJuIGMoYil9LEJBU0U2NC5kZWNvZGVBU0NJST1mdW5jdGlvbihhKXt2YXIgYj1lKGEpO3JldHVybiBmLmRlY29kZShiKX0sQkFTRTY0LmVuY29kZT1mdW5jdGlvbihhKXt2YXIgYj1VVEY4LmVuY29kZShhKTtyZXR1cm4gYyhiKX0sQkFTRTY0LmRlY29kZT1mdW5jdGlvbihhKXt2YXIgYj1lKGEpO3JldHVybiBVVEY4LmRlY29kZShiKX19KFwiQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrL1wiKSx2b2lkIDA9PT1idG9hKXZhciBidG9hPUJBU0U2NC5lbmNvZGU7aWYodm9pZCAwPT09YXRvYil2YXIgYXRvYj1CQVNFNjQuZGVjb2RlO01lZGlhUGxheWVyPWZ1bmN0aW9uKGEpe1widXNlIHN0cmljdFwiO3ZhciBiLGMsZCxlLGYsZz1cIjEuMC4wXCIsaD1hLGk9ITEsaj0hMSxrPSEwLGw9ITEsbT1NZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuQnVmZmVyRXh0ZW5zaW9ucy5CVUZGRVJfU0laRV9SRVFVSVJFRCxuPWZ1bmN0aW9uKCl7cmV0dXJuISFjJiYhIWR9LG89ZnVuY3Rpb24oKXtpZighaSl0aHJvd1wiTWVkaWFQbGF5ZXIgbm90IGluaXRpYWxpemVkIVwiO2lmKCF0aGlzLmNhcGFiaWxpdGllcy5zdXBwb3J0c01lZGlhU291cmNlKCkpcmV0dXJuIHRoaXMuZXJySGFuZGxlci5jYXBhYmlsaXR5RXJyb3IoXCJtZWRpYXNvdXJjZVwiKSx2b2lkIDA7aWYoIWN8fCFkKXRocm93XCJNaXNzaW5nIHZpZXcgb3Igc291cmNlLlwiO2o9ITAsdGhpcy5kZWJ1Zy5sb2coXCJQbGF5YmFjayBpbml0aWF0ZWQhXCIpLGU9Yi5nZXRPYmplY3QoXCJzdHJlYW1Db250cm9sbGVyXCIpLGUuc2V0VmlkZW9Nb2RlbChmKSxlLnNldEF1dG9QbGF5KGspLGUubG9hZChkKSxiLm1hcFZhbHVlKFwic2NoZWR1bGVXaGlsZVBhdXNlZFwiLGwpLGIubWFwT3V0bGV0KFwic2NoZWR1bGVXaGlsZVBhdXNlZFwiLFwic3RyZWFtXCIpLGIubWFwVmFsdWUoXCJidWZmZXJNYXhcIixtKSxiLmluamVjdEludG8odGhpcy5idWZmZXJFeHQsXCJidWZmZXJNYXhcIil9LHA9ZnVuY3Rpb24oKXtuKCkmJm8uY2FsbCh0aGlzKX07cmV0dXJuIGI9bmV3IGRpam9uLlN5c3RlbSxiLm1hcFZhbHVlKFwic3lzdGVtXCIsYiksYi5tYXBPdXRsZXQoXCJzeXN0ZW1cIiksYi5pbmplY3RJbnRvKGgpLHtkZWJ1Zzp2b2lkIDAsZXZlbnRCdXM6dm9pZCAwLGNhcGFiaWxpdGllczp2b2lkIDAsYWJyQ29udHJvbGxlcjp2b2lkIDAsbWV0cmljc01vZGVsOnZvaWQgMCxtZXRyaWNzRXh0OnZvaWQgMCxidWZmZXJFeHQ6dm9pZCAwLGFkZEV2ZW50TGlzdGVuZXI6ZnVuY3Rpb24oYSxiLGMpe3RoaXMuZXZlbnRCdXMuYWRkRXZlbnRMaXN0ZW5lcihhLGIsYyl9LHJlbW92ZUV2ZW50TGlzdGVuZXI6ZnVuY3Rpb24oYSxiLGMpe3RoaXMuZXZlbnRCdXMucmVtb3ZlRXZlbnRMaXN0ZW5lcihhLGIsYyl9LGdldFZlcnNpb246ZnVuY3Rpb24oKXtyZXR1cm4gZ30sc3RhcnR1cDpmdW5jdGlvbigpe2l8fChiLmluamVjdEludG8odGhpcyksaT0hMCl9LGdldERlYnVnOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZGVidWd9LGdldFZpZGVvTW9kZWw6ZnVuY3Rpb24oKXtyZXR1cm4gZn0sc2V0QXV0b1BsYXk6ZnVuY3Rpb24oYSl7az1hfSxnZXRBdXRvUGxheTpmdW5jdGlvbigpe3JldHVybiBrfSxzZXRTY2hlZHVsZVdoaWxlUGF1c2VkOmZ1bmN0aW9uKGEpe2w9YX0sZ2V0U2NoZWR1bGVXaGlsZVBhdXNlZDpmdW5jdGlvbigpe3JldHVybiBsfSxzZXRCdWZmZXJNYXg6ZnVuY3Rpb24oYSl7bT1hfSxnZXRCdWZmZXJNYXg6ZnVuY3Rpb24oKXtyZXR1cm4gbX0sZ2V0TWV0cmljc0V4dDpmdW5jdGlvbigpe3JldHVybiB0aGlzLm1ldHJpY3NFeHR9LGdldE1ldHJpY3NGb3I6ZnVuY3Rpb24oYSl7dmFyIGI9dGhpcy5tZXRyaWNzTW9kZWwuZ2V0UmVhZE9ubHlNZXRyaWNzRm9yKGEpO3JldHVybiBifSxnZXRRdWFsaXR5Rm9yOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmFickNvbnRyb2xsZXIuZ2V0UXVhbGl0eUZvcihhKX0sc2V0UXVhbGl0eUZvcjpmdW5jdGlvbihhLGIpe3RoaXMuYWJyQ29udHJvbGxlci5zZXRQbGF5YmFja1F1YWxpdHkoYSxiKX0sZ2V0QXV0b1N3aXRjaFF1YWxpdHk6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5hYnJDb250cm9sbGVyLmdldEF1dG9Td2l0Y2hCaXRyYXRlKCl9LHNldEF1dG9Td2l0Y2hRdWFsaXR5OmZ1bmN0aW9uKGEpe3RoaXMuYWJyQ29udHJvbGxlci5zZXRBdXRvU3dpdGNoQml0cmF0ZShhKX0sYXR0YWNoVmlldzpmdW5jdGlvbihhKXtpZighaSl0aHJvd1wiTWVkaWFQbGF5ZXIgbm90IGluaXRpYWxpemVkIVwiO2M9YSxmPW51bGwsYyYmKGY9Yi5nZXRPYmplY3QoXCJ2aWRlb01vZGVsXCIpLGYuc2V0RWxlbWVudChjKSksaiYmZSYmKGUucmVzZXQoKSxlPW51bGwsaj0hMSksbi5jYWxsKHRoaXMpJiZwLmNhbGwodGhpcyl9LGF0dGFjaFNvdXJjZTpmdW5jdGlvbihhKXtpZighaSl0aHJvd1wiTWVkaWFQbGF5ZXIgbm90IGluaXRpYWxpemVkIVwiO2Q9YSx0aGlzLnNldFF1YWxpdHlGb3IoXCJ2aWRlb1wiLDApLHRoaXMuc2V0UXVhbGl0eUZvcihcImF1ZGlvXCIsMCksaiYmZSYmKGUucmVzZXQoKSxlPW51bGwsaj0hMSksbi5jYWxsKHRoaXMpJiZwLmNhbGwodGhpcyl9LHJlc2V0OmZ1bmN0aW9uKCl7dGhpcy5hdHRhY2hTb3VyY2UobnVsbCksdGhpcy5hdHRhY2hWaWV3KG51bGwpfSxwbGF5Om8saXNSZWFkeTpufX0sTWVkaWFQbGF5ZXIucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllcn0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzPXt9LE1lZGlhUGxheWVyLnV0aWxzPXt9LE1lZGlhUGxheWVyLm1vZGVscz17fSxNZWRpYVBsYXllci52bz17fSxNZWRpYVBsYXllci52by5tZXRyaWNzPXt9LE1lZGlhUGxheWVyLnJ1bGVzPXt9LE1lZGlhUGxheWVyLmRpPXt9LE1lZGlhUGxheWVyLmRpLkNvbnRleHQ9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjtyZXR1cm57c3lzdGVtOnZvaWQgMCxzZXR1cDpmdW5jdGlvbigpe3RoaXMuc3lzdGVtLmF1dG9NYXBPdXRsZXRzPSEwLHRoaXMuc3lzdGVtLm1hcFNpbmdsZXRvbihcImRlYnVnXCIsTWVkaWFQbGF5ZXIudXRpbHMuRGVidWcpLHRoaXMuc3lzdGVtLm1hcFNpbmdsZXRvbihcImV2ZW50QnVzXCIsTWVkaWFQbGF5ZXIudXRpbHMuRXZlbnRCdXMpLHRoaXMuc3lzdGVtLm1hcFNpbmdsZXRvbihcImNhcGFiaWxpdGllc1wiLE1lZGlhUGxheWVyLnV0aWxzLkNhcGFiaWxpdGllcyksdGhpcy5zeXN0ZW0ubWFwU2luZ2xldG9uKFwidGV4dFRyYWNrRXh0ZW5zaW9uc1wiLE1lZGlhUGxheWVyLnV0aWxzLlRleHRUcmFja0V4dGVuc2lvbnMpLHRoaXMuc3lzdGVtLm1hcFNpbmdsZXRvbihcInZ0dFBhcnNlclwiLE1lZGlhUGxheWVyLnV0aWxzLlZUVFBhcnNlciksdGhpcy5zeXN0ZW0ubWFwQ2xhc3MoXCJ2aWRlb01vZGVsXCIsTWVkaWFQbGF5ZXIubW9kZWxzLlZpZGVvTW9kZWwpLHRoaXMuc3lzdGVtLm1hcFNpbmdsZXRvbihcIm1hbmlmZXN0TW9kZWxcIixNZWRpYVBsYXllci5tb2RlbHMuTWFuaWZlc3RNb2RlbCksdGhpcy5zeXN0ZW0ubWFwU2luZ2xldG9uKFwibWV0cmljc01vZGVsXCIsTWVkaWFQbGF5ZXIubW9kZWxzLk1ldHJpY3NNb2RlbCksdGhpcy5zeXN0ZW0ubWFwQ2xhc3MoXCJwcm90ZWN0aW9uTW9kZWxcIixNZWRpYVBsYXllci5tb2RlbHMuUHJvdGVjdGlvbk1vZGVsKSx0aGlzLnN5c3RlbS5tYXBTaW5nbGV0b24oXCJ0ZXh0VlRUU291cmNlQnVmZmVyXCIsTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlRleHRWVFRTb3VyY2VCdWZmZXIpLHRoaXMuc3lzdGVtLm1hcFNpbmdsZXRvbihcIm1lZGlhU291cmNlRXh0XCIsTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLk1lZGlhU291cmNlRXh0ZW5zaW9ucyksdGhpcy5zeXN0ZW0ubWFwU2luZ2xldG9uKFwic291cmNlQnVmZmVyRXh0XCIsTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlNvdXJjZUJ1ZmZlckV4dGVuc2lvbnMpLHRoaXMuc3lzdGVtLm1hcFNpbmdsZXRvbihcImJ1ZmZlckV4dFwiLE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5CdWZmZXJFeHRlbnNpb25zKSx0aGlzLnN5c3RlbS5tYXBTaW5nbGV0b24oXCJhYnJDb250cm9sbGVyXCIsTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLkFickNvbnRyb2xsZXIpLHRoaXMuc3lzdGVtLm1hcFNpbmdsZXRvbihcImVyckhhbmRsZXJcIixNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuRXJyb3JIYW5kbGVyKSx0aGlzLnN5c3RlbS5tYXBTaW5nbGV0b24oXCJwcm90ZWN0aW9uRXh0XCIsTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlByb3RlY3Rpb25FeHRlbnNpb25zKSx0aGlzLnN5c3RlbS5tYXBDbGFzcyhcInByb3RlY3Rpb25Db250cm9sbGVyXCIsTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlByb3RlY3Rpb25Db250cm9sbGVyKSx0aGlzLnN5c3RlbS5tYXBDbGFzcyhcIm1ldHJpY3NcIixNZWRpYVBsYXllci5tb2RlbHMuTWV0cmljc0xpc3QpLHRoaXMuc3lzdGVtLm1hcENsYXNzKFwiZG93bmxvYWRSYXRpb1J1bGVcIixNZWRpYVBsYXllci5ydWxlcy5Eb3dubG9hZFJhdGlvUnVsZSksdGhpcy5zeXN0ZW0ubWFwQ2xhc3MoXCJpbnN1ZmZpY2llbnRCdWZmZXJSdWxlXCIsTWVkaWFQbGF5ZXIucnVsZXMuSW5zdWZmaWNpZW50QnVmZmVyUnVsZSksdGhpcy5zeXN0ZW0ubWFwQ2xhc3MoXCJsaW1pdFN3aXRjaGVzUnVsZVwiLE1lZGlhUGxheWVyLnJ1bGVzLkxpbWl0U3dpdGNoZXNSdWxlKSx0aGlzLnN5c3RlbS5tYXBDbGFzcyhcImFiclJ1bGVzQ29sbGVjdGlvblwiLE1lZGlhUGxheWVyLnJ1bGVzLkJhc2VSdWxlc0NvbGxlY3Rpb24pLHRoaXMuc3lzdGVtLm1hcENsYXNzKFwidGV4dENvbnRyb2xsZXJcIixNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuVGV4dENvbnRyb2xsZXIpLHRoaXMuc3lzdGVtLm1hcENsYXNzKFwiYnVmZmVyQ29udHJvbGxlclwiLE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5CdWZmZXJDb250cm9sbGVyKSx0aGlzLnN5c3RlbS5tYXBDbGFzcyhcIm1hbmlmZXN0TG9hZGVyXCIsTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLk1hbmlmZXN0TG9hZGVyKSx0aGlzLnN5c3RlbS5tYXBDbGFzcyhcIm1hbmlmZXN0VXBkYXRlclwiLE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5NYW5pZmVzdFVwZGF0ZXIpLHRoaXMuc3lzdGVtLm1hcENsYXNzKFwiZnJhZ21lbnRDb250cm9sbGVyXCIsTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLkZyYWdtZW50Q29udHJvbGxlciksdGhpcy5zeXN0ZW0ubWFwQ2xhc3MoXCJmcmFnbWVudExvYWRlclwiLE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5GcmFnbWVudExvYWRlciksdGhpcy5zeXN0ZW0ubWFwQ2xhc3MoXCJmcmFnbWVudE1vZGVsXCIsTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLkZyYWdtZW50TW9kZWwpLHRoaXMuc3lzdGVtLm1hcFNpbmdsZXRvbihcInN0cmVhbUNvbnRyb2xsZXJcIixNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuU3RyZWFtQ29udHJvbGxlciksdGhpcy5zeXN0ZW0ubWFwQ2xhc3MoXCJzdHJlYW1cIixNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuU3RyZWFtKSx0aGlzLnN5c3RlbS5tYXBDbGFzcyhcInJlcXVlc3RTY2hlZHVsZXJcIixNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuUmVxdWVzdFNjaGVkdWxlciksdGhpcy5zeXN0ZW0ubWFwU2luZ2xldG9uKFwic2NoZWR1bGVyRXh0XCIsTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlNjaGVkdWxlckV4dGVuc2lvbnMpLHRoaXMuc3lzdGVtLm1hcENsYXNzKFwic2NoZWR1bGVyTW9kZWxcIixNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuU2NoZWR1bGVyTW9kZWwpXHJcbn19fSxEYXNoPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7cmV0dXJue21vZHVsZXM6e30sZGVwZW5kZW5jaWVzOnt9LHZvOnt9LGRpOnt9fX0oKSxEYXNoLmRpLkRhc2hDb250ZXh0PWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7cmV0dXJue3N5c3RlbTp2b2lkIDAsc2V0dXA6ZnVuY3Rpb24oKXtEYXNoLmRpLkRhc2hDb250ZXh0LnByb3RvdHlwZS5zZXR1cC5jYWxsKHRoaXMpLHRoaXMuc3lzdGVtLm1hcENsYXNzKFwicGFyc2VyXCIsRGFzaC5kZXBlbmRlbmNpZXMuRGFzaFBhcnNlciksdGhpcy5zeXN0ZW0ubWFwQ2xhc3MoXCJpbmRleEhhbmRsZXJcIixEYXNoLmRlcGVuZGVuY2llcy5EYXNoSGFuZGxlciksdGhpcy5zeXN0ZW0ubWFwQ2xhc3MoXCJiYXNlVVJMRXh0XCIsRGFzaC5kZXBlbmRlbmNpZXMuQmFzZVVSTEV4dGVuc2lvbnMpLHRoaXMuc3lzdGVtLm1hcENsYXNzKFwiZnJhZ21lbnRFeHRcIixEYXNoLmRlcGVuZGVuY2llcy5GcmFnbWVudEV4dGVuc2lvbnMpLHRoaXMuc3lzdGVtLm1hcFNpbmdsZXRvbihcIm1hbmlmZXN0RXh0XCIsRGFzaC5kZXBlbmRlbmNpZXMuRGFzaE1hbmlmZXN0RXh0ZW5zaW9ucyksdGhpcy5zeXN0ZW0ubWFwU2luZ2xldG9uKFwibWV0cmljc0V4dFwiLERhc2guZGVwZW5kZW5jaWVzLkRhc2hNZXRyaWNzRXh0ZW5zaW9ucyl9fX0sRGFzaC5kaS5EYXNoQ29udGV4dC5wcm90b3R5cGU9bmV3IE1lZGlhUGxheWVyLmRpLkNvbnRleHQsRGFzaC5kaS5EYXNoQ29udGV4dC5wcm90b3R5cGUuY29uc3RydWN0b3I9RGFzaC5kaS5EYXNoQ29udGV4dCxEYXNoLmRlcGVuZGVuY2llcy5CYXNlVVJMRXh0ZW5zaW9ucz1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3ZhciBhPWZ1bmN0aW9uKGEsYil7Zm9yKHZhciBjLGQsZSxmLGcsaCxpLGosayxsLG09bmV3IERhdGFWaWV3KGEpLG49e30sbz0wO1wic2lkeFwiIT09aiYmbzxtLmJ5dGVMZW5ndGg7KXtmb3Ioaz1tLmdldFVpbnQzMihvKSxvKz00LGo9XCJcIixmPTA7ND5mO2YrPTEpbD1tLmdldEludDgobyksais9U3RyaW5nLmZyb21DaGFyQ29kZShsKSxvKz0xO1wibW9vZlwiIT09aiYmXCJ0cmFmXCIhPT1qJiZcInNpZHhcIiE9PWo/bys9ay04Olwic2lkeFwiPT09aiYmKG8tPTgpfWlmKGU9bS5nZXRVaW50MzIobywhMSkrbyxlPmEuYnl0ZUxlbmd0aCl0aHJvd1wic2lkeCB0ZXJtaW5hdGVzIGFmdGVyIGFycmF5IGJ1ZmZlclwiO2ZvcihuLnZlcnNpb249bS5nZXRVaW50OChvKzgpLG8rPTEyLG4udGltZXNjYWxlPW0uZ2V0VWludDMyKG8rNCwhMSksbys9OCwwPT09bi52ZXJzaW9uPyhuLmVhcmxpZXN0X3ByZXNlbnRhdGlvbl90aW1lPW0uZ2V0VWludDMyKG8sITEpLG4uZmlyc3Rfb2Zmc2V0PW0uZ2V0VWludDMyKG8rNCwhMSksbys9OCk6KG4uZWFybGllc3RfcHJlc2VudGF0aW9uX3RpbWU9dXRpbHMuTWF0aC50bzY0Qml0TnVtYmVyKG0uZ2V0VWludDMyKG8rNCwhMSksbS5nZXRVaW50MzIobywhMSkpLG4uZmlyc3Rfb2Zmc2V0PShtLmdldFVpbnQzMihvKzgsITEpPDwzMikrbS5nZXRVaW50MzIobysxMiwhMSksbys9MTYpLG4uZmlyc3Rfb2Zmc2V0Kz1lKyhifHwwKSxuLnJlZmVyZW5jZV9jb3VudD1tLmdldFVpbnQxNihvKzIsITEpLG8rPTQsbi5yZWZlcmVuY2VzPVtdLGM9bi5maXJzdF9vZmZzZXQsZD1uLmVhcmxpZXN0X3ByZXNlbnRhdGlvbl90aW1lLGY9MDtmPG4ucmVmZXJlbmNlX2NvdW50O2YrPTEpaD1tLmdldFVpbnQzMihvLCExKSxnPWg+Pj4zMSxoPTIxNDc0ODM2NDcmaCxpPW0uZ2V0VWludDMyKG8rNCwhMSksbys9MTIsbi5yZWZlcmVuY2VzLnB1c2goe3NpemU6aCx0eXBlOmcsb2Zmc2V0OmMsZHVyYXRpb246aSx0aW1lOmQsdGltZXNjYWxlOm4udGltZXNjYWxlfSksYys9aCxkKz1pO2lmKG8hPT1lKXRocm93XCJFcnJvcjogZmluYWwgcG9zIFwiK28rXCIgZGlmZmVycyBmcm9tIFNJRFggZW5kIFwiK2U7cmV0dXJuIG59LGI9ZnVuY3Rpb24oYixjLGQpe3ZhciBlLGYsZyxoLGksaixrLGw7Zm9yKGU9YS5jYWxsKHRoaXMsYixkKSxmPWUucmVmZXJlbmNlcyxnPVtdLGk9MCxqPWYubGVuZ3RoO2o+aTtpKz0xKWg9bmV3IERhc2gudm8uU2VnbWVudCxoLmR1cmF0aW9uPWZbaV0uZHVyYXRpb24saC5tZWRpYT1jLGguc3RhcnRUaW1lPWZbaV0udGltZSxoLnRpbWVzY2FsZT1mW2ldLnRpbWVzY2FsZSxrPWZbaV0ub2Zmc2V0LGw9ZltpXS5vZmZzZXQrZltpXS5zaXplLTEsaC5tZWRpYVJhbmdlPWsrXCItXCIrbCxnLnB1c2goaCk7cmV0dXJuIHRoaXMuZGVidWcubG9nKFwiUGFyc2VkIFNJRFggYm94OiBcIitnLmxlbmd0aCtcIiBzZWdtZW50cy5cIiksUS53aGVuKGcpfSxjPWZ1bmN0aW9uKGEsYil7dmFyIGQsZSxmLGcsaCxpLGosaz1RLmRlZmVyKCksbD1uZXcgRGF0YVZpZXcoYSksbT0wLG49XCJcIixvPTAscD0hMSxxPXRoaXM7Zm9yKHEuZGVidWcubG9nKFwiU2VhcmNoaW5nIGZvciBpbml0aWFsaXphdGlvbi5cIik7XCJtb292XCIhPT1uJiZtPGwuYnl0ZUxlbmd0aDspe2ZvcihvPWwuZ2V0VWludDMyKG0pLG0rPTQsbj1cIlwiLGc9MDs0Pmc7Zys9MSloPWwuZ2V0SW50OChtKSxuKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGgpLG0rPTE7XCJtb292XCIhPT1uJiYobSs9by04KX1yZXR1cm4gZj1sLmJ5dGVMZW5ndGgtbSxcIm1vb3ZcIiE9PW4/KHEuZGVidWcubG9nKFwiTG9hZGluZyBtb3JlIGJ5dGVzIHRvIGZpbmQgaW5pdGlhbGl6YXRpb24uXCIpLGIucmFuZ2Uuc3RhcnQ9MCxiLnJhbmdlLmVuZD1iLmJ5dGVzTG9hZGVkK2IuYnl0ZXNUb0xvYWQsaT1uZXcgWE1MSHR0cFJlcXVlc3QsaS5vbmxvYWRlbmQ9ZnVuY3Rpb24oKXtwfHxrLnJlamVjdChcIkVycm9yIGxvYWRpbmcgaW5pdGlhbGl6YXRpb24uXCIpfSxpLm9ubG9hZD1mdW5jdGlvbigpe3A9ITAsYi5ieXRlc0xvYWRlZD1iLnJhbmdlLmVuZCxjLmNhbGwocSxpLnJlc3BvbnNlKS50aGVuKGZ1bmN0aW9uKGEpe2sucmVzb2x2ZShhKX0pfSxpLm9uZXJyb3I9ZnVuY3Rpb24oKXtrLnJlamVjdChcIkVycm9yIGxvYWRpbmcgaW5pdGlhbGl6YXRpb24uXCIpfSxpLm9wZW4oXCJHRVRcIixiLnVybCksaS5yZXNwb25zZVR5cGU9XCJhcnJheWJ1ZmZlclwiLGkuc2V0UmVxdWVzdEhlYWRlcihcIlJhbmdlXCIsXCJieXRlcz1cIitiLnJhbmdlLnN0YXJ0K1wiLVwiK2IucmFuZ2UuZW5kKSxpLnNlbmQobnVsbCkpOihkPW0tOCxlPWQrby0xLGo9ZCtcIi1cIitlLHEuZGVidWcubG9nKFwiRm91bmQgdGhlIGluaXRpYWxpemF0aW9uLiAgUmFuZ2U6IFwiK2opLGsucmVzb2x2ZShqKSksay5wcm9taXNlfSxkPWZ1bmN0aW9uKGEpe3ZhciBiPVEuZGVmZXIoKSxkPW5ldyBYTUxIdHRwUmVxdWVzdCxlPSEwLGY9dGhpcyxnPXt1cmw6YSxyYW5nZTp7fSxzZWFyY2hpbmc6ITEsYnl0ZXNMb2FkZWQ6MCxieXRlc1RvTG9hZDoxNTAwLHJlcXVlc3Q6ZH07cmV0dXJuIGYuZGVidWcubG9nKFwiU3RhcnQgc2VhcmNoaW5nIGZvciBpbml0aWFsaXphdGlvbi5cIiksZy5yYW5nZS5zdGFydD0wLGcucmFuZ2UuZW5kPWcuYnl0ZXNUb0xvYWQsZC5vbmxvYWQ9ZnVuY3Rpb24oKXtkLnN0YXR1czwyMDB8fGQuc3RhdHVzPjI5OXx8KGU9ITEsZy5ieXRlc0xvYWRlZD1nLnJhbmdlLmVuZCxjLmNhbGwoZixkLnJlc3BvbnNlLGcpLnRoZW4oZnVuY3Rpb24oYSl7Yi5yZXNvbHZlKGEpfSkpfSxkLm9ubG9hZGVuZD1kLm9uZXJyb3I9ZnVuY3Rpb24oKXtlJiYoZT0hMSxmLmVyckhhbmRsZXIuZG93bmxvYWRFcnJvcihcImluaXRpYWxpemF0aW9uXCIsZy51cmwsZCksYi5yZWplY3QoZCkpfSxkLm9wZW4oXCJHRVRcIixnLnVybCksZC5yZXNwb25zZVR5cGU9XCJhcnJheWJ1ZmZlclwiLGQuc2V0UmVxdWVzdEhlYWRlcihcIlJhbmdlXCIsXCJieXRlcz1cIitnLnJhbmdlLnN0YXJ0K1wiLVwiK2cucmFuZ2UuZW5kKSxkLnNlbmQobnVsbCksZi5kZWJ1Zy5sb2coXCJQZXJmb3JtIGluaXQgc2VhcmNoOiBcIitnLnVybCksYi5wcm9taXNlfSxlPWZ1bmN0aW9uKGEsYyl7dmFyIGQsZixnLGgsaSxqLGssbCxtPVEuZGVmZXIoKSxuPW5ldyBEYXRhVmlldyhhKSxvPW5ldyBYTUxIdHRwUmVxdWVzdCxwPTAscT1cIlwiLHI9MCxzPSEwLHQ9ITEsdT10aGlzO2Zvcih1LmRlYnVnLmxvZyhcIlNlYXJjaGluZyBmb3IgU0lEWCBib3guXCIpLHUuZGVidWcubG9nKGMuYnl0ZXNMb2FkZWQrXCIgYnl0ZXMgbG9hZGVkLlwiKTtcInNpZHhcIiE9PXEmJnA8bi5ieXRlTGVuZ3RoOyl7Zm9yKHI9bi5nZXRVaW50MzIocCkscCs9NCxxPVwiXCIsaT0wOzQ+aTtpKz0xKWo9bi5nZXRJbnQ4KHApLHErPVN0cmluZy5mcm9tQ2hhckNvZGUoaikscCs9MTtcInNpZHhcIiE9PXEmJihwKz1yLTgpfWlmKGQ9bi5ieXRlTGVuZ3RoLXAsXCJzaWR4XCIhPT1xKW0ucmVqZWN0KCk7ZWxzZSBpZihyLTg+ZCl1LmRlYnVnLmxvZyhcIkZvdW5kIFNJRFggYnV0IHdlIGRvbid0IGhhdmUgYWxsIG9mIGl0LlwiKSxjLnJhbmdlLnN0YXJ0PTAsYy5yYW5nZS5lbmQ9Yy5ieXRlc0xvYWRlZCsoci1kKSxvLm9ubG9hZD1mdW5jdGlvbigpe28uc3RhdHVzPDIwMHx8by5zdGF0dXM+Mjk5fHwocz0hMSxjLmJ5dGVzTG9hZGVkPWMucmFuZ2UuZW5kLGUuY2FsbCh1LG8ucmVzcG9uc2UsYykudGhlbihmdW5jdGlvbihhKXttLnJlc29sdmUoYSl9KSl9LG8ub25sb2FkZW5kPW8ub25lcnJvcj1mdW5jdGlvbigpe3MmJihzPSExLHUuZXJySGFuZGxlci5kb3dubG9hZEVycm9yKFwiU0lEWFwiLGMudXJsLG8pLG0ucmVqZWN0KG8pKX0sby5vcGVuKFwiR0VUXCIsYy51cmwpLG8ucmVzcG9uc2VUeXBlPVwiYXJyYXlidWZmZXJcIixvLnNldFJlcXVlc3RIZWFkZXIoXCJSYW5nZVwiLFwiYnl0ZXM9XCIrYy5yYW5nZS5zdGFydCtcIi1cIitjLnJhbmdlLmVuZCksby5zZW5kKG51bGwpO2Vsc2UgaWYoYy5yYW5nZS5zdGFydD1wLTgsYy5yYW5nZS5lbmQ9Yy5yYW5nZS5zdGFydCtyLHUuZGVidWcubG9nKFwiRm91bmQgdGhlIFNJRFggYm94LiAgU3RhcnQ6IFwiK2MucmFuZ2Uuc3RhcnQrXCIgfCBFbmQ6IFwiK2MucmFuZ2UuZW5kKSxmPW5ldyBBcnJheUJ1ZmZlcihjLnJhbmdlLmVuZC1jLnJhbmdlLnN0YXJ0KSxoPW5ldyBVaW50OEFycmF5KGYpLGc9bmV3IFVpbnQ4QXJyYXkoYSxjLnJhbmdlLnN0YXJ0LGMucmFuZ2UuZW5kLWMucmFuZ2Uuc3RhcnQpLGguc2V0KGcpLGs9dGhpcy5wYXJzZVNJRFguY2FsbCh0aGlzLGYsYy5yYW5nZS5zdGFydCksbD1rLnJlZmVyZW5jZXMsbnVsbCE9PWwmJnZvaWQgMCE9PWwmJmwubGVuZ3RoPjAmJih0PTE9PT1sWzBdLnR5cGUpLHQpe3UuZGVidWcubG9nKFwiSW5pdGlhdGUgbXVsdGlwbGUgU0lEWCBsb2FkLlwiKTt2YXIgdix3LHgseSx6LEEsQj1bXTtmb3Iodj0wLHc9bC5sZW5ndGg7dz52O3YrPTEpeD1sW3ZdLm9mZnNldCx5PWxbdl0ub2Zmc2V0K2xbdl0uc2l6ZS0xLHo9eCtcIi1cIit5LEIucHVzaCh0aGlzLmxvYWRTZWdtZW50cy5jYWxsKHUsYy51cmwseikpO1EuYWxsKEIpLnRoZW4oZnVuY3Rpb24oYSl7Zm9yKEE9W10sdj0wLHc9YS5sZW5ndGg7dz52O3YrPTEpQT1BLmNvbmNhdChhW3ZdKTttLnJlc29sdmUoQSl9LGZ1bmN0aW9uKGEpe20ucmVqZWN0KGEpfSl9ZWxzZSB1LmRlYnVnLmxvZyhcIlBhcnNpbmcgc2VnbWVudHMgZnJvbSBTSURYLlwiKSxiLmNhbGwodSxmLGMudXJsLGMucmFuZ2Uuc3RhcnQpLnRoZW4oZnVuY3Rpb24oYSl7bS5yZXNvbHZlKGEpfSk7cmV0dXJuIG0ucHJvbWlzZX0sZj1mdW5jdGlvbihhLGMpe3ZhciBkLGY9US5kZWZlcigpLGc9bmV3IFhNTEh0dHBSZXF1ZXN0LGg9ITAsaT10aGlzLGo9e3VybDphLHJhbmdlOnt9LHNlYXJjaGluZzohMSxieXRlc0xvYWRlZDowLGJ5dGVzVG9Mb2FkOjE1MDAscmVxdWVzdDpnfTtyZXR1cm4gbnVsbD09PWM/KGkuZGVidWcubG9nKFwiTm8ga25vd24gcmFuZ2UgZm9yIFNJRFggcmVxdWVzdC5cIiksai5zZWFyY2hpbmc9ITAsai5yYW5nZS5zdGFydD0wLGoucmFuZ2UuZW5kPWouYnl0ZXNUb0xvYWQpOihkPWMuc3BsaXQoXCItXCIpLGoucmFuZ2Uuc3RhcnQ9cGFyc2VGbG9hdChkWzBdKSxqLnJhbmdlLmVuZD1wYXJzZUZsb2F0KGRbMV0pKSxnLm9ubG9hZD1mdW5jdGlvbigpe2cuc3RhdHVzPDIwMHx8Zy5zdGF0dXM+Mjk5fHwoaD0hMSxqLnNlYXJjaGluZz8oai5ieXRlc0xvYWRlZD1qLnJhbmdlLmVuZCxlLmNhbGwoaSxnLnJlc3BvbnNlLGopLnRoZW4oZnVuY3Rpb24oYSl7Zi5yZXNvbHZlKGEpfSkpOmIuY2FsbChpLGcucmVzcG9uc2Usai51cmwsai5yYW5nZS5zdGFydCkudGhlbihmdW5jdGlvbihhKXtmLnJlc29sdmUoYSl9KSl9LGcub25sb2FkZW5kPWcub25lcnJvcj1mdW5jdGlvbigpe2gmJihoPSExLGkuZXJySGFuZGxlci5kb3dubG9hZEVycm9yKFwiU0lEWFwiLGoudXJsLGcpLGYucmVqZWN0KGcpKX0sZy5vcGVuKFwiR0VUXCIsai51cmwpLGcucmVzcG9uc2VUeXBlPVwiYXJyYXlidWZmZXJcIixnLnNldFJlcXVlc3RIZWFkZXIoXCJSYW5nZVwiLFwiYnl0ZXM9XCIrai5yYW5nZS5zdGFydCtcIi1cIitqLnJhbmdlLmVuZCksZy5zZW5kKG51bGwpLGkuZGVidWcubG9nKFwiUGVyZm9ybSBTSURYIGxvYWQ6IFwiK2oudXJsKSxmLnByb21pc2V9O3JldHVybntkZWJ1Zzp2b2lkIDAsZXJySGFuZGxlcjp2b2lkIDAsbG9hZFNlZ21lbnRzOmYsbG9hZEluaXRpYWxpemF0aW9uOmQscGFyc2VTZWdtZW50czpiLHBhcnNlU0lEWDphLGZpbmRTSURYOmV9fSxEYXNoLmRlcGVuZGVuY2llcy5CYXNlVVJMRXh0ZW5zaW9ucy5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOkRhc2guZGVwZW5kZW5jaWVzLkJhc2VVUkxFeHRlbnNpb25zfSxEYXNoLmRlcGVuZGVuY2llcy5EYXNoSGFuZGxlcj1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3ZhciBhLGIsYyxkPS0xLGU9ZnVuY3Rpb24oYSxiKXt2YXIgYz1udWxsO3JldHVybiBiJiZiLlJlcHJlc2VudGF0aW9uX2FzQXJyYXkmJmIuUmVwcmVzZW50YXRpb25fYXNBcnJheS5sZW5ndGg+MCYmKGM9Yi5SZXByZXNlbnRhdGlvbl9hc0FycmF5W2FdKSxjfSxmPWZ1bmN0aW9uKGEsYil7dmFyIGM9Yi50b1N0cmluZygpO3JldHVybiBhLnNwbGl0KFwiJE51bWJlciRcIikuam9pbihjKX0sZz1mdW5jdGlvbihhLGIpe3ZhciBjPWIudG9TdHJpbmcoKTtyZXR1cm4gYS5zcGxpdChcIiRUaW1lJFwiKS5qb2luKGMpfSxoPWZ1bmN0aW9uKGEsYil7dmFyIGM9Yi50b1N0cmluZygpO3JldHVybiBhLnNwbGl0KFwiJEJhbmR3aWR0aCRcIikuam9pbihjKX0saT1mdW5jdGlvbihhLGIpe2lmKG51bGw9PT1ifHwtMT09PWEuaW5kZXhPZihcIiRSZXByZXNlbnRhdGlvbklEJFwiKSlyZXR1cm4gYTt2YXIgYz1iLnRvU3RyaW5nKCk7cmV0dXJuIGEuc3BsaXQoXCIkUmVwcmVzZW50YXRpb25JRCRcIikuam9pbihjKX0saj1mdW5jdGlvbihhLGIpe3ZhciBjO3JldHVybiBjPWE9PT1iP2E6LTEhPT1hLmluZGV4T2YoXCJodHRwOi8vXCIpP2E6YithfSxrPWZ1bmN0aW9uKGEsYil7dmFyIGQ9US5kZWZlcigpLGY9ZShhLGIpLGc9bnVsbCxrPW51bGwsbD1udWxsLG09bnVsbCxuPXRoaXM7cmV0dXJuIGY/KG4uZGVidWcubG9nKFwiR2V0dGluZyB0aGUgaW5pdGlhbGl6YXRpb24gcmVxdWVzdC5cIiksZi5oYXNPd25Qcm9wZXJ0eShcIlNlZ21lbnRUZW1wbGF0ZVwiKT9mLlNlZ21lbnRUZW1wbGF0ZS5oYXNPd25Qcm9wZXJ0eShcImluaXRpYWxpemF0aW9uXCIpJiYoaz1mLlNlZ21lbnRUZW1wbGF0ZS5pbml0aWFsaXphdGlvbixrPWgoayxmLmJhbmR3aWR0aCksaz1pKGssZi5pZCkpOmYuaGFzT3duUHJvcGVydHkoXCJTZWdtZW50TGlzdFwiKSYmZi5TZWdtZW50TGlzdC5oYXNPd25Qcm9wZXJ0eShcIkluaXRpYWxpemF0aW9uXCIpJiZmLlNlZ21lbnRMaXN0LkluaXRpYWxpemF0aW9uLmhhc093blByb3BlcnR5KFwicmFuZ2VcIik/KGs9Zi5TZWdtZW50TGlzdC5Jbml0aWFsaXphdGlvbi5oYXNPd25Qcm9wZXJ0eShcInNvdXJjZVVSTFwiKT9mLlNlZ21lbnRMaXN0LkluaXRpYWxpemF0aW9uLnNvdXJjZVVSTDpmLkJhc2VVUkwsbT1mLlNlZ21lbnRMaXN0LkluaXRpYWxpemF0aW9uLnJhbmdlKTpmLmhhc093blByb3BlcnR5KFwiU2VnbWVudExpc3RcIikmJmYuU2VnbWVudExpc3QuaGFzT3duUHJvcGVydHkoXCJJbml0aWFsaXphdGlvblwiKSYmZi5TZWdtZW50TGlzdC5Jbml0aWFsaXphdGlvbi5oYXNPd25Qcm9wZXJ0eShcInNvdXJjZVVSTFwiKT9rPWYuU2VnbWVudExpc3QuSW5pdGlhbGl6YXRpb24uc291cmNlVVJMOmYuaGFzT3duUHJvcGVydHkoXCJTZWdtZW50QmFzZVwiKSYmZi5TZWdtZW50QmFzZS5oYXNPd25Qcm9wZXJ0eShcIkluaXRpYWxpemF0aW9uXCIpJiZmLlNlZ21lbnRCYXNlLkluaXRpYWxpemF0aW9uLmhhc093blByb3BlcnR5KFwicmFuZ2VcIik/KGs9Zi5CYXNlVVJMLG09Zi5TZWdtZW50QmFzZS5Jbml0aWFsaXphdGlvbi5yYW5nZSk6Zi5oYXNPd25Qcm9wZXJ0eShcIm1pbWVUeXBlXCIpJiZuLm1hbmlmZXN0RXh0LmdldElzVGV4dFRyYWNrKGYubWltZVR5cGUpPyhrPWYuQmFzZVVSTCxtPTApOihsPWYuQmFzZVVSTCxuLmJhc2VVUkxFeHQubG9hZEluaXRpYWxpemF0aW9uKGwpLnRoZW4oZnVuY3Rpb24oYil7bi5kZWJ1Zy5sb2coXCJHb3QgYW4gaW5pdGlhbGl6YXRpb24uXCIpLGc9bmV3IE1lZGlhUGxheWVyLnZvLlNlZ21lbnRSZXF1ZXN0LGcuc3RyZWFtVHlwZT1jLGcudHlwZT1cIkluaXRpYWxpemF0aW9uIFNlZ21lbnRcIixnLnVybD1qKGwsZi5CYXNlVVJMKSxnLnJhbmdlPWIsZy5xdWFsaXR5PWEsZC5yZXNvbHZlKGcpfSxmdW5jdGlvbihhKXtkLnJlamVjdChhKX0pKSxrJiZrLmxlbmd0aD4wJiYobi5kZWJ1Zy5sb2coXCJHb3QgYW4gaW5pdGlhbGl6YXRpb24uXCIpLGc9bmV3IE1lZGlhUGxheWVyLnZvLlNlZ21lbnRSZXF1ZXN0LGcuc3RyZWFtVHlwZT1jLGcudHlwZT1cIkluaXRpYWxpemF0aW9uIFNlZ21lbnRcIixnLnVybD1qKGssZi5CYXNlVVJMKSxnLnJhbmdlPW0sZy5xdWFsaXR5PWEsZC5yZXNvbHZlKGcpKSxkLnByb21pc2UpOlEucmVqZWN0KFwibm8gcmVwcmVzZW5hdGlvblwiKX0sbD1mdW5jdGlvbihjKXt2YXIgZSxmLGcsaCxpLGosaz0hMTtyZXR1cm4gdGhpcy5kZWJ1Zy5sb2coXCJDaGVja2luZyBmb3Igc3RyZWFtIGVuZC4uLlwiKSxhPyh0aGlzLmRlYnVnLmxvZyhcIkxpdmUgbmV2ZXIgZW5kcyEgKFRPRE8pXCIpLGs9ITEpOmMuaGFzT3duUHJvcGVydHkoXCJzZWdtZW50c1wiKSYmbnVsbCE9PWMuc2VnbWVudHM/KHRoaXMuZGVidWcubG9nKFwiU2VnbWVudHM6IFwiK2QrXCIgLyBcIitjLnNlZ21lbnRzLmxlbmd0aCksaz1kPj1jLnNlZ21lbnRzLmxlbmd0aCk6Yy5oYXNPd25Qcm9wZXJ0eShcIlNlZ21lbnRUZW1wbGF0ZVwiKSYmIWMuU2VnbWVudFRlbXBsYXRlLmhhc093blByb3BlcnR5KFwiU2VnbWVudFRpbWVsaW5lXCIpJiYoZj0xLGk9MSxoPWIsYy5TZWdtZW50VGVtcGxhdGUuaGFzT3duUHJvcGVydHkoXCJkdXJhdGlvblwiKSYmKGU9Yy5TZWdtZW50VGVtcGxhdGUuZHVyYXRpb24sYy5TZWdtZW50VGVtcGxhdGUuaGFzT3duUHJvcGVydHkoXCJ0aW1lc2NhbGVcIikmJihmPWMuU2VnbWVudFRlbXBsYXRlLnRpbWVzY2FsZSksYy5TZWdtZW50VGVtcGxhdGUuaGFzT3duUHJvcGVydHkoXCJzdGFydE51bWJlclwiKSYmKGk9Yy5TZWdtZW50VGVtcGxhdGUuc3RhcnROdW1iZXIpLGc9ZS9mLGo9ZC1pLHRoaXMuZGVidWcubG9nKFwiU2VnbWVudFRlbXBsYXRlOiBcIitnK1wiICogXCIraitcIiA9IFwiK2cqaitcIiAvIFwiK2gpLGs9ZypqPj1oKSksUS53aGVuKGspfSxtPWZ1bmN0aW9uKGEsYyl7dmFyIGQsZSxoLGksaixrLGwsbSxuPVtdLG89MCxwPTEscT0xO2ZvcihhLmhhc093blByb3BlcnR5KFwic3RhcnROdW1iZXJcIikmJihwPWEuc3RhcnROdW1iZXIpLGEuaGFzT3duUHJvcGVydHkoXCJ0aW1lc2NhbGVcIikmJihxPWEudGltZXNjYWxlKSxkPWMuU19hc0FycmF5LGg9MCxpPWQubGVuZ3RoO2k+aDtoKz0xKWZvcihlPWRbaF0saz0wLGUuaGFzT3duUHJvcGVydHkoXCJyXCIpJiYoaz1lLnIpLDA+ayYmKGs9KGItby9xKS8oZS5kL3EpLTEpLGo9MDtrPj1qO2orPTEpbD1uZXcgRGFzaC52by5TZWdtZW50LGwudGltZXNjYWxlPXEsMD09PWomJmUuaGFzT3duUHJvcGVydHkoXCJ0XCIpPyhsLnN0YXJ0VGltZT1lLnQsbz1lLnQpOmwuc3RhcnRUaW1lPW8sbC5kdXJhdGlvbj1lLmQsbT1hLm1lZGlhLG09ZihtLHApLG09ZyhtLGwuc3RhcnRUaW1lKSxsLm1lZGlhPW0sbi5wdXNoKGwpLG8rPWwuZHVyYXRpb24scCs9MTtyZXR1cm4gUS53aGVuKG4pfSxuPWZ1bmN0aW9uKGEpe3ZhciBiLGMsZCxlLGYsZz1bXSxoPTE7Zm9yKGEuaGFzT3duUHJvcGVydHkoXCJzdGFydE51bWJlclwiKSYmKGg9TWF0aC5tYXgoYS5zdGFydE51bWJlciwxKSksZj0oaC0xKSphLmR1cmF0aW9uLGI9MCxjPWEuU2VnbWVudFVSTF9hc0FycmF5Lmxlbmd0aDtjPmI7Yis9MSllPWEuU2VnbWVudFVSTF9hc0FycmF5W2JdLGQ9bmV3IERhc2gudm8uU2VnbWVudCxkLm1lZGlhPWUubWVkaWEsZC5tZWRpYVJhbmdlPWUubWVkaWFSYW5nZSxkLmluZGV4PWUuaW5kZXgsZC5pbmRleFJhbmdlPWUuaW5kZXhSYW5nZSxkLnRpbWVzY2FsZT1hLnRpbWVzY2FsZSxkLmR1cmF0aW9uPWEuZHVyYXRpb24sZC5zdGFydFRpbWU9ZitiKmEuZHVyYXRpb24sZy5wdXNoKGQpO3JldHVybiBRLndoZW4oZyl9LG89ZnVuY3Rpb24oYSl7dmFyIGI9YS5CYXNlVVJMLGM9bnVsbDtyZXR1cm4gYS5oYXNPd25Qcm9wZXJ0eShcIlNlZ21lbnRCYXNlXCIpJiZhLlNlZ21lbnRCYXNlLmhhc093blByb3BlcnR5KFwiaW5kZXhSYW5nZVwiKSYmKGM9YS5TZWdtZW50QmFzZS5pbmRleFJhbmdlKSx0aGlzLmJhc2VVUkxFeHQubG9hZFNlZ21lbnRzKGIsYyl9LHA9ZnVuY3Rpb24oYSl7dmFyIGI7cmV0dXJuIGI9YS5oYXNPd25Qcm9wZXJ0eShcIlNlZ21lbnRUZW1wbGF0ZVwiKSYmIWEuU2VnbWVudFRlbXBsYXRlLmhhc093blByb3BlcnR5KFwiU2VnbWVudFRpbWVsaW5lXCIpP1Eud2hlbihudWxsKTphLmhhc093blByb3BlcnR5KFwic2VnbWVudHNcIikmJm51bGwhPT1hLnNlZ21lbnRzP1Eud2hlbihhLnNlZ21lbnRzKTphLmhhc093blByb3BlcnR5KFwiU2VnbWVudFRlbXBsYXRlXCIpJiZhLlNlZ21lbnRUZW1wbGF0ZS5oYXNPd25Qcm9wZXJ0eShcIlNlZ21lbnRUaW1lbGluZVwiKT9tLmNhbGwodGhpcyxhLlNlZ21lbnRUZW1wbGF0ZSxhLlNlZ21lbnRUZW1wbGF0ZS5TZWdtZW50VGltZWxpbmUpOmEuaGFzT3duUHJvcGVydHkoXCJTZWdtZW50TGlzdFwiKT9uLmNhbGwodGhpcyxhLlNlZ21lbnRMaXN0KTpvLmNhbGwodGhpcyxhKX0scT1mdW5jdGlvbihhLGIpe3ZhciBjLGQsZSxmLGc9LTE7aWYoYiYmYi5sZW5ndGg+MClmb3IoZj1iLmxlbmd0aC0xO2Y+PTA7Zi0tKXtpZihjPWJbZl0sZD1jLnN0YXJ0VGltZS9jLnRpbWVzY2FsZSxlPWMuZHVyYXRpb24vYy50aW1lc2NhbGUsYStEYXNoLmRlcGVuZGVuY2llcy5EYXNoSGFuZGxlci5FUFNJTE9OPj1kJiZhLURhc2guZGVwZW5kZW5jaWVzLkRhc2hIYW5kbGVyLkVQU0lMT048PWQrZSl7Zz1mO2JyZWFrfS0xPT09ZyYmYS1EYXNoLmRlcGVuZGVuY2llcy5EYXNoSGFuZGxlci5FUFNJTE9OPmQrZSYmKGc9ZisxKX1yZXR1cm4tMT09PWcmJihjb25zb2xlLmxvZyhcIkNvdWxkbid0IGZpZ3VyZSBvdXQgYSB0aW1lIVwiKSxjb25zb2xlLmxvZyhcIlRpbWU6IFwiK2EpLGNvbnNvbGUubG9nKGIpKSxRLndoZW4oZyl9LHI9ZnVuY3Rpb24oYSxiKXt2YXIgYyxkLGU9LTEsZj0xLGc9MTtpZighYi5oYXNPd25Qcm9wZXJ0eShcImR1cmF0aW9uXCIpKXRocm93XCJFeHBlY3RlZCAnZHVyYXRpb24nIGF0dHJpYnV0ZSBvbiBTZWdtZW50VGVtcGxhdGUhXCI7cmV0dXJuIGM9Yi5kdXJhdGlvbixiLmhhc093blByb3BlcnR5KFwidGltZXNjYWxlXCIpJiYoZj1iLnRpbWVzY2FsZSksYi5oYXNPd25Qcm9wZXJ0eShcInN0YXJ0TnVtYmVyXCIpJiYoZz1iLnN0YXJ0TnVtYmVyKSxkPWMvZixlPU1hdGguZmxvb3IoYS9kKSxlKz1nLFEud2hlbihlKX0scz1mdW5jdGlvbihhLGIsZCxlKXt2YXIgayxsLG09bmV3IE1lZGlhUGxheWVyLnZvLlNlZ21lbnRSZXF1ZXN0LG49MSxvPTE7cmV0dXJuIGIuaGFzT3duUHJvcGVydHkoXCJ0aW1lc2NhbGVcIikmJihuPWIudGltZXNjYWxlKSxiLmhhc093blByb3BlcnR5KFwic3RhcnROdW1iZXJcIikmJihvPWIuc3RhcnROdW1iZXIpLGw9Yi5kdXJhdGlvbiphL24sbD1NYXRoLmZsb29yKGwpLGs9Yi5tZWRpYSxrPWYoayxhKSxrPWcoayxsKSxrPWgoayxkLmJhbmR3aWR0aCksaz1pKGssZC5pZCksbS5zdHJlYW1UeXBlPWMsbS50eXBlPVwiTWVkaWEgU2VnbWVudFwiLG0udXJsPWooayxkLkJhc2VVUkwpLG0uZHVyYXRpb249Yi5kdXJhdGlvbi9uLG0udGltZXNjYWxlPW4sbS5zdGFydFRpbWU9KGEtbykqYi5kdXJhdGlvbi9uLG0ucXVhbGl0eT1lLG0uaW5kZXg9YSxRLndoZW4obSl9LHQ9ZnVuY3Rpb24oYSxiLGQsZSl7aWYobnVsbD09PWJ8fHZvaWQgMD09PWIpcmV0dXJuIFEud2hlbihudWxsKTt2YXIgayxsPW5ldyBNZWRpYVBsYXllci52by5TZWdtZW50UmVxdWVzdDtyZXR1cm4gaz1qKGIubWVkaWEsZC5CYXNlVVJMKSxrPWYoayxhKSxrPWcoayxiLnN0YXJ0VGltZSksaz1oKGssZC5iYW5kd2lkdGgpLGs9aShrLGQuaWQpLGwuc3RyZWFtVHlwZT1jLGwudHlwZT1cIk1lZGlhIFNlZ21lbnRcIixsLnVybD1rLGwucmFuZ2U9Yi5tZWRpYVJhbmdlLGwuc3RhcnRUaW1lPWIuc3RhcnRUaW1lL2IudGltZXNjYWxlLGwuZHVyYXRpb249Yi5kdXJhdGlvbi9iLnRpbWVzY2FsZSxsLnRpbWVzY2FsZT1iLnRpbWVzY2FsZSxsLnF1YWxpdHk9ZSxsLmluZGV4PWEsUS53aGVuKGwpfSx1PWZ1bmN0aW9uKGEsYixjKXt2YXIgZixnLGgsaT1lKGIsYyksaj0hMSxrPXRoaXM7cmV0dXJuIGk/KGsuZGVidWcubG9nKFwiR2V0dGluZyB0aGUgcmVxdWVzdCBmb3IgdGltZTogXCIrYSksZj1RLmRlZmVyKCkscC5jYWxsKGssaSkudGhlbihmdW5jdGlvbihiKXt2YXIgYztpZihrLmRlYnVnLmxvZyhcIkdvdCBzZWdtZW50cy5cIiksay5kZWJ1Zy5sb2coYiksbnVsbD09PWIpe2lmKCFpLmhhc093blByb3BlcnR5KFwiU2VnbWVudFRlbXBsYXRlXCIpKXRocm93XCJFeHBlY3RlZCBTZWdtZW50VGVtcGxhdGUhXCI7aj0hMCxrLmRlYnVnLmxvZyhcIk5vIHNlZ21lbnRzIGZvdW5kLCBzbyB3ZSBtdXN0IGJlIHVzaW5nIGEgU2VnbWVudFRlbXBsYXRlLlwiKSxjPXIuY2FsbChrLGEsaS5TZWdtZW50VGVtcGxhdGUpfWVsc2Ugay5kZWJ1Zy5sb2coXCJHb3QgYSBsaXN0IG9mIHNlZ21lbnRzLCBzbyBkaWcgZGVlcGVyLlwiKSxpLnNlZ21lbnRzPWIsaj0hMSxjPXEuY2FsbChrLGEsYik7cmV0dXJuIGN9LGZ1bmN0aW9uKCl7Zi5yZWplY3QoKX0pLnRoZW4oZnVuY3Rpb24oYil7cmV0dXJuIGsuZGVidWcubG9nKFwiSW5kZXggZm9yIHRpbWUgXCIrYStcIiBpcyBcIitiKSxkPWIsbC5jYWxsKGssaSl9KS50aGVuKGZ1bmN0aW9uKGEpe3ZhciBjPW51bGw7cmV0dXJuIGsuZGVidWcubG9nKFwiU3RyZWFtIGZpbmlzaGVkPyBcIithKSxhPyhnPW5ldyBNZWRpYVBsYXllci52by5TZWdtZW50UmVxdWVzdCxnLmFjdGlvbj1nLkFDVElPTl9DT01QTEVURSxnLmluZGV4PWQsay5kZWJ1Zy5sb2coXCJTaWduYWwgY29tcGxldGUuXCIpLGsuZGVidWcubG9nKGcpLGYucmVzb2x2ZShnKSk6aj9jPXMuY2FsbChrLGQsaS5TZWdtZW50VGVtcGxhdGUsaSxiKTooaD1pLnNlZ21lbnRzW2RdLGM9dC5jYWxsKGssZCxoLGksYikpLGN9KS50aGVuKGZ1bmN0aW9uKGEpe2suZGVidWcubG9nKFwiR290IGEgcmVxdWVzdC5cIiksay5kZWJ1Zy5sb2coYSksZi5yZXNvbHZlKGEpfSksZi5wcm9taXNlKTpRLnJlamVjdChcIm5vIHJlcHJlc2VuYXRpb25cIil9LHY9ZnVuY3Rpb24oYSxiKXt2YXIgYyxmLGcsaD1lKGEsYiksaT10aGlzO2lmKCFoKXJldHVybiBRLnJlamVjdChcIm5vIHJlcHJlc2VuYXRpb25cIik7aWYoaS5kZWJ1Zy5sb2coXCJHZXR0aW5nIHRoZSBuZXh0IHJlcXVlc3QuXCIpLC0xPT09ZCl0aHJvd1wiWW91IG11c3QgY2FsbCBnZXRTZWdtZW50UmVxdWVzdEZvclRpbWUgZmlyc3QuXCI7cmV0dXJuIGQrPTEsaS5kZWJ1Zy5sb2coXCJOZXcgaW5kZXg6IFwiK2QpLGM9US5kZWZlcigpLGwuY2FsbChpLGgpLnRoZW4oZnVuY3Rpb24oYil7aS5kZWJ1Zy5sb2coXCJTdHJlYW0gZmluaXNoZWQ/IFwiK2IpLGI/KGY9bmV3IE1lZGlhUGxheWVyLnZvLlNlZ21lbnRSZXF1ZXN0LGYuYWN0aW9uPWYuQUNUSU9OX0NPTVBMRVRFLGYuaW5kZXg9ZCxpLmRlYnVnLmxvZyhcIlNpZ25hbCBjb21wbGV0ZS5cIiksaS5kZWJ1Zy5sb2coZiksYy5yZXNvbHZlKGYpKTpwLmNhbGwoaSxoKS50aGVuKGZ1bmN0aW9uKGIpe3ZhciBjO2lmKGkuZGVidWcubG9nKFwiR290IHNlZ21lbnRzLlwiKSxpLmRlYnVnLmxvZyhiKSxudWxsPT09Yil7aWYoIWguaGFzT3duUHJvcGVydHkoXCJTZWdtZW50VGVtcGxhdGVcIikpdGhyb3dcIkV4cGVjdGVkIFNlZ21lbnRUZW1wbGF0ZSFcIjtpLmRlYnVnLmxvZyhcIk5vIHNlZ21lbnRzIGZvdW5kLCBzbyB3ZSBtdXN0IGJlIHVzaW5nIGEgU2VnbWVudFRlbXBsYXRlLlwiKSxjPXMuY2FsbChpLGQsaC5TZWdtZW50VGVtcGxhdGUsaCxhKX1lbHNlIGguc2VnbWVudHM9YixnPWguc2VnbWVudHNbZF0sYz10LmNhbGwoaSxkLGcsaCxhKTtyZXR1cm4gY30sZnVuY3Rpb24oKXtjLnJlamVjdCgpfSkudGhlbihmdW5jdGlvbihhKXtpLmRlYnVnLmxvZyhcIkdvdCBhIHJlcXVlc3QuXCIpLGkuZGVidWcubG9nKGEpLGMucmVzb2x2ZShhKX0pfSksYy5wcm9taXNlfSx3PWZ1bmN0aW9uKGEsYixjLGQpe3ZhciBmLGcsaCxpPXRoaXMsaj1lKGEsYiksaz1NYXRoLm1heChjLWQsMCksbD1RLmRlZmVyKCksbT0wLG49MTtyZXR1cm4gaj8ocC5jYWxsKGksaikudGhlbihmdW5jdGlvbihhKXtpZihudWxsPT09YXx8dm9pZCAwPT09YSl7aWYoIWouaGFzT3duUHJvcGVydHkoXCJTZWdtZW50VGVtcGxhdGVcIikpdGhyb3dcIkV4cGVjdGVkIFNlZ21lbnRUZW1wbGF0ZSFcIjtqLlNlZ21lbnRUZW1wbGF0ZS5oYXNPd25Qcm9wZXJ0eShcInRpbWVzY2FsZVwiKSYmKG49ai5TZWdtZW50VGVtcGxhdGUudGltZXNjYWxlKSxoPWouU2VnbWVudFRlbXBsYXRlLmR1cmF0aW9uLGY9aC9ufWVsc2UgZz1hWzBdLGcuaGFzT3duUHJvcGVydHkoXCJ0aW1lc2NhbGVcIikmJihuPWcudGltZXNjYWxlKSxoPWcuZHVyYXRpb24sZj1oL247bT1NYXRoLmNlaWwoay9mKSxsLnJlc29sdmUobSl9LGZ1bmN0aW9uKCl7bC5yZXNvbHZlKDApfSksbC5wcm9taXNlKTpRLnJlamVjdChcIm5vIHJlcHJlc2VuYXRpb25cIil9LHg9ZnVuY3Rpb24oYixjKXt2YXIgZixnLGgsaSxqPXRoaXMsaz1lKGIsYyksbD0hMSxtPTEsbj0xLG89US5kZWZlcigpO3JldHVybiBrPyhnPWQsMD5nJiYobD1hLGc9MCkscC5jYWxsKGosaykudGhlbihmdW5jdGlvbihhKXtpZihudWxsPT09YXx8dm9pZCAwPT09YSl7aWYoIWsuaGFzT3duUHJvcGVydHkoXCJTZWdtZW50VGVtcGxhdGVcIikpdGhyb3dcIkV4cGVjdGVkIFNlZ21lbnRUZW1wbGF0ZSFcIjtpPWsuU2VnbWVudFRlbXBsYXRlLmR1cmF0aW9uLGsuU2VnbWVudFRlbXBsYXRlLmhhc093blByb3BlcnR5KFwidGltZXNjYWxlXCIpJiYobT1rLlNlZ21lbnRUZW1wbGF0ZS50aW1lc2NhbGUpLGsuU2VnbWVudFRlbXBsYXRlLmhhc093blByb3BlcnR5KFwic3RhcnROdW1iZXJcIikmJihuPWsuU2VnbWVudFRlbXBsYXRlLnN0YXJ0TnVtYmVyKSxmPWkvbSpNYXRoLm1heChnLW4sMCl9ZWxzZShsfHxnPj1hLmxlbmd0aCkmJihnPWEubGVuZ3RoLTEpLGg9YVtnXS5zdGFydFRpbWUsaT1hW2ddLmR1cmF0aW9uLGFbZ10uaGFzT3duUHJvcGVydHkoXCJ0aW1lc2NhbGVcIikmJihtPWFbZ10udGltZXNjYWxlKSxmPWgvbTtvLnJlc29sdmUoZil9LGZ1bmN0aW9uKCl7by5yZWplY3QoKX0pLG8ucHJvbWlzZSk6US5yZWplY3QoXCJubyByZXByZXNlbmF0aW9uXCIpfTtyZXR1cm57ZGVidWc6dm9pZCAwLGJhc2VVUkxFeHQ6dm9pZCAwLG1hbmlmZXN0TW9kZWw6dm9pZCAwLG1hbmlmZXN0RXh0OnZvaWQgMCxlcnJIYW5kbGVyOnZvaWQgMCxnZXRUeXBlOmZ1bmN0aW9uKCl7cmV0dXJuIGN9LHNldFR5cGU6ZnVuY3Rpb24oYSl7Yz1hfSxnZXRJc0xpdmU6ZnVuY3Rpb24oKXtyZXR1cm4gYX0sc2V0SXNMaXZlOmZ1bmN0aW9uKGIpe2E9Yn0sZ2V0RHVyYXRpb246ZnVuY3Rpb24oKXtyZXR1cm4gYn0sc2V0RHVyYXRpb246ZnVuY3Rpb24oYSl7Yj1hfSxnZXRJbml0UmVxdWVzdDprLGdldFNlZ21lbnRSZXF1ZXN0Rm9yVGltZTp1LGdldE5leHRTZWdtZW50UmVxdWVzdDp2LGdldEN1cnJlbnRUaW1lOngsZ2V0U2VnbWVudENvdW50Rm9yRHVyYXRpb246d319LERhc2guZGVwZW5kZW5jaWVzLkRhc2hIYW5kbGVyLkVQU0lMT049LjAwMyxEYXNoLmRlcGVuZGVuY2llcy5EYXNoSGFuZGxlci5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOkRhc2guZGVwZW5kZW5jaWVzLkRhc2hIYW5kbGVyfSxEYXNoLmRlcGVuZGVuY2llcy5EYXNoTWFuaWZlc3RFeHRlbnNpb25zPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCJ9LERhc2guZGVwZW5kZW5jaWVzLkRhc2hNYW5pZmVzdEV4dGVuc2lvbnMucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpEYXNoLmRlcGVuZGVuY2llcy5EYXNoTWFuaWZlc3RFeHRlbnNpb25zLGdldElzQXVkaW86ZnVuY3Rpb24oYSl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGIsYyxkLGU9YS5Db250ZW50Q29tcG9uZW50X2FzQXJyYXksZj0hMSxnPSExO2lmKGUpZm9yKGI9MCxjPWUubGVuZ3RoO2M+YjtiKz0xKVwiYXVkaW9cIj09PWVbYl0uY29udGVudFR5cGUmJihmPSEwLGc9ITApO2lmKGEuaGFzT3duUHJvcGVydHkoXCJtaW1lVHlwZVwiKSYmKGY9LTEhPT1hLm1pbWVUeXBlLmluZGV4T2YoXCJhdWRpb1wiKSxnPSEwKSwhZylmb3IoYj0wLGM9YS5SZXByZXNlbnRhdGlvbl9hc0FycmF5Lmxlbmd0aDshZyYmYz5iOylkPWEuUmVwcmVzZW50YXRpb25fYXNBcnJheVtiXSxkLmhhc093blByb3BlcnR5KFwibWltZVR5cGVcIikmJihmPS0xIT09ZC5taW1lVHlwZS5pbmRleE9mKFwiYXVkaW9cIiksZz0hMCksYis9MTtyZXR1cm4gZiYmKGEudHlwZT1cImF1ZGlvXCIpLFEud2hlbihmKX0sZ2V0SXNWaWRlbzpmdW5jdGlvbihhKXtcInVzZSBzdHJpY3RcIjt2YXIgYixjLGQsZT1hLkNvbnRlbnRDb21wb25lbnRfYXNBcnJheSxmPSExLGc9ITE7aWYoZSlmb3IoYj0wLGM9ZS5sZW5ndGg7Yz5iO2IrPTEpXCJ2aWRlb1wiPT09ZVtiXS5jb250ZW50VHlwZSYmKGY9ITAsZz0hMCk7aWYoYS5oYXNPd25Qcm9wZXJ0eShcIm1pbWVUeXBlXCIpJiYoZj0tMSE9PWEubWltZVR5cGUuaW5kZXhPZihcInZpZGVvXCIpLGc9ITApLCFnKWZvcihiPTAsYz1hLlJlcHJlc2VudGF0aW9uX2FzQXJyYXkubGVuZ3RoOyFnJiZjPmI7KWQ9YS5SZXByZXNlbnRhdGlvbl9hc0FycmF5W2JdLGQuaGFzT3duUHJvcGVydHkoXCJtaW1lVHlwZVwiKSYmKGY9LTEhPT1kLm1pbWVUeXBlLmluZGV4T2YoXCJ2aWRlb1wiKSxnPSEwKSxiKz0xO3JldHVybiBmJiYoYS50eXBlPVwidmlkZW9cIiksUS53aGVuKGYpfSxnZXRJc1RleHQ6ZnVuY3Rpb24oYSl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGIsYyxkLGU9YS5Db250ZW50Q29tcG9uZW50X2FzQXJyYXksZj0hMSxnPSExO2lmKGUpZm9yKGI9MCxjPWUubGVuZ3RoO2M+YjtiKz0xKVwidGV4dFwiPT09ZVtiXS5jb250ZW50VHlwZSYmKGY9ITAsZz0hMCk7aWYoYS5oYXNPd25Qcm9wZXJ0eShcIm1pbWVUeXBlXCIpJiYoZj0tMSE9PWEubWltZVR5cGUuaW5kZXhPZihcInRleHRcIiksZz0hMCksIWcpZm9yKGI9MCxjPWEuUmVwcmVzZW50YXRpb25fYXNBcnJheS5sZW5ndGg7IWcmJmM+YjspZD1hLlJlcHJlc2VudGF0aW9uX2FzQXJyYXlbYl0sZC5oYXNPd25Qcm9wZXJ0eShcIm1pbWVUeXBlXCIpJiYoZj0tMSE9PWQubWltZVR5cGUuaW5kZXhPZihcInRleHRcIiksZz0hMCksYis9MTtyZXR1cm4gUS53aGVuKGYpfSxnZXRJc1RleHRUcmFjazpmdW5jdGlvbihhKXtyZXR1cm5cInRleHQvdnR0XCI9PT1hfHxcImFwcGxpY2F0aW9uL3R0bWwreG1sXCI9PT1hfSxnZXRJc01haW46ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjtyZXR1cm4gUS53aGVuKCExKX0scHJvY2Vzc0FkYXB0YXRpb246ZnVuY3Rpb24oYSl7XCJ1c2Ugc3RyaWN0XCI7cmV0dXJuIHZvaWQgMCE9PWEuUmVwcmVzZW50YXRpb25fYXNBcnJheSYmbnVsbCE9PWEuUmVwcmVzZW50YXRpb25fYXNBcnJheSYmYS5SZXByZXNlbnRhdGlvbl9hc0FycmF5LnNvcnQoZnVuY3Rpb24oYSxiKXtyZXR1cm4gYS5iYW5kd2lkdGgtYi5iYW5kd2lkdGh9KSxhfSxnZXREYXRhRm9ySWQ6ZnVuY3Rpb24oYSxiLGMpe1widXNlIHN0cmljdFwiO3ZhciBkLGUsZj1iLlBlcmlvZF9hc0FycmF5W2NdLkFkYXB0YXRpb25TZXRfYXNBcnJheTtmb3IoZD0wLGU9Zi5sZW5ndGg7ZT5kO2QrPTEpaWYoZltkXS5oYXNPd25Qcm9wZXJ0eShcImlkXCIpJiZmW2RdLmlkPT09YSlyZXR1cm4gUS53aGVuKGZbZF0pO3JldHVybiBRLndoZW4obnVsbCl9LGdldERhdGFGb3JJbmRleDpmdW5jdGlvbihhLGIsYyl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGQ9Yi5QZXJpb2RfYXNBcnJheVtjXS5BZGFwdGF0aW9uU2V0X2FzQXJyYXk7cmV0dXJuIFEud2hlbihkW2FdKX0sZ2V0RGF0YUluZGV4OmZ1bmN0aW9uKGEsYixjKXtcInVzZSBzdHJpY3RcIjt2YXIgZCxlLGY9Yi5QZXJpb2RfYXNBcnJheVtjXS5BZGFwdGF0aW9uU2V0X2FzQXJyYXk7Zm9yKGQ9MCxlPWYubGVuZ3RoO2U+ZDtkKz0xKWlmKGZbZF09PT1hKXJldHVybiBRLndoZW4oZCk7cmV0dXJuIFEud2hlbigtMSl9LGdldFZpZGVvRGF0YTpmdW5jdGlvbihhLGIpe1widXNlIHN0cmljdFwiO3ZhciBjLGQsZT10aGlzLGY9YS5QZXJpb2RfYXNBcnJheVtiXS5BZGFwdGF0aW9uU2V0X2FzQXJyYXksZz1RLmRlZmVyKCksaD1bXTtmb3IoYz0wLGQ9Zi5sZW5ndGg7ZD5jO2MrPTEpaC5wdXNoKHRoaXMuZ2V0SXNWaWRlbyhmW2NdKSk7cmV0dXJuIFEuYWxsKGgpLnRoZW4oZnVuY3Rpb24oYSl7dmFyIGI9ITE7Zm9yKGM9MCxkPWEubGVuZ3RoO2Q+YztjKz0xKWFbY109PT0hMCYmKGI9ITAsZy5yZXNvbHZlKGUucHJvY2Vzc0FkYXB0YXRpb24oZltjXSkpKTtifHxnLnJlc29sdmUobnVsbCl9KSxnLnByb21pc2V9LGdldFRleHREYXRhOmZ1bmN0aW9uKGEsYil7XCJ1c2Ugc3RyaWN0XCI7dmFyIGMsZCxlPXRoaXMsZj1hLlBlcmlvZF9hc0FycmF5W2JdLkFkYXB0YXRpb25TZXRfYXNBcnJheSxnPVEuZGVmZXIoKSxoPVtdO2ZvcihjPTAsZD1mLmxlbmd0aDtkPmM7Yys9MSloLnB1c2godGhpcy5nZXRJc1RleHQoZltjXSkpO3JldHVybiBRLmFsbChoKS50aGVuKGZ1bmN0aW9uKGEpe3ZhciBiPSExO2ZvcihjPTAsZD1hLmxlbmd0aDtkPmM7Yys9MSlhW2NdPT09ITAmJihiPSEwLGcucmVzb2x2ZShlLnByb2Nlc3NBZGFwdGF0aW9uKGZbY10pKSk7Ynx8Zy5yZXNvbHZlKG51bGwpfSksZy5wcm9taXNlfSxnZXRBdWRpb0RhdGFzOmZ1bmN0aW9uKGEsYil7XCJ1c2Ugc3RyaWN0XCI7dmFyIGMsZCxlPXRoaXMsZj1hLlBlcmlvZF9hc0FycmF5W2JdLkFkYXB0YXRpb25TZXRfYXNBcnJheSxnPVEuZGVmZXIoKSxoPVtdO2ZvcihjPTAsZD1mLmxlbmd0aDtkPmM7Yys9MSloLnB1c2godGhpcy5nZXRJc0F1ZGlvKGZbY10pKTtyZXR1cm4gUS5hbGwoaCkudGhlbihmdW5jdGlvbihhKXt2YXIgYj1bXTtmb3IoYz0wLGQ9YS5sZW5ndGg7ZD5jO2MrPTEpYVtjXT09PSEwJiZiLnB1c2goZS5wcm9jZXNzQWRhcHRhdGlvbihmW2NdKSk7Zy5yZXNvbHZlKGIpfSksZy5wcm9taXNlfSxnZXRQcmltYXJ5QXVkaW9EYXRhOmZ1bmN0aW9uKGEsYil7XCJ1c2Ugc3RyaWN0XCI7dmFyIGMsZCxlPVEuZGVmZXIoKSxmPVtdLGc9dGhpcztyZXR1cm4gdGhpcy5nZXRBdWRpb0RhdGFzKGEsYikudGhlbihmdW5jdGlvbihhKXtmb3IoYSYmMCE9PWEubGVuZ3RofHxlLnJlc29sdmUobnVsbCksYz0wLGQ9YS5sZW5ndGg7ZD5jO2MrPTEpZi5wdXNoKGcuZ2V0SXNNYWluKGFbY10pKTtRLmFsbChmKS50aGVuKGZ1bmN0aW9uKGIpe3ZhciBmPSExO2ZvcihjPTAsZD1iLmxlbmd0aDtkPmM7Yys9MSliW2NdPT09ITAmJihmPSEwLGUucmVzb2x2ZShnLnByb2Nlc3NBZGFwdGF0aW9uKGFbY10pKSk7Znx8ZS5yZXNvbHZlKGFbMF0pfSl9KSxlLnByb21pc2V9LGdldENvZGVjOmZ1bmN0aW9uKGEpe1widXNlIHN0cmljdFwiO3ZhciBiPWEuUmVwcmVzZW50YXRpb25fYXNBcnJheVswXSxjPWIubWltZVR5cGUrJztjb2RlY3M9XCInK2IuY29kZWNzKydcIic7cmV0dXJuIFEud2hlbihjKX0sZ2V0TWltZVR5cGU6ZnVuY3Rpb24oYSl7XCJ1c2Ugc3RyaWN0XCI7cmV0dXJuIFEud2hlbihhLlJlcHJlc2VudGF0aW9uX2FzQXJyYXlbMF0ubWltZVR5cGUpfSxnZXRLSUQ6ZnVuY3Rpb24oYSl7XCJ1c2Ugc3RyaWN0XCI7cmV0dXJuIGEmJmEuaGFzT3duUHJvcGVydHkoXCJjZW5jOmRlZmF1bHRfS0lEXCIpP2FbXCJjZW5jOmRlZmF1bHRfS0lEXCJdOm51bGx9LGdldENvbnRlbnRQcm90ZWN0aW9uRGF0YTpmdW5jdGlvbihhKXtcInVzZSBzdHJpY3RcIjtyZXR1cm4gYSYmYS5oYXNPd25Qcm9wZXJ0eShcIkNvbnRlbnRQcm90ZWN0aW9uX2FzQXJyYXlcIikmJjAhPT1hLkNvbnRlbnRQcm90ZWN0aW9uX2FzQXJyYXkubGVuZ3RoP1Eud2hlbihhLkNvbnRlbnRQcm90ZWN0aW9uX2FzQXJyYXkpOlEud2hlbihudWxsKX0sZ2V0U2VnbWVudEluZm9Gb3I6ZnVuY3Rpb24oYSl7cmV0dXJuIGEuaGFzT3duUHJvcGVydHkoXCJTZWdtZW50QmFzZVwiKT9hLlNlZ21lbnRCYXNlOmEuaGFzT3duUHJvcGVydHkoXCJTZWdtZW50TGlzdFwiKT9hLlNlZ21lbnRMaXN0OmEuaGFzT3duUHJvcGVydHkoXCJTZWdtZW50VGVtcGxhdGVcIik/YS5TZWdtZW50VGVtcGxhdGU6bnVsbH0sZ2V0TGl2ZU9mZnNldDpmdW5jdGlvbihhKXtcInVzZSBzdHJpY3RcIjt2YXIgYj0xNTtyZXR1cm4gYS5oYXNPd25Qcm9wZXJ0eShcInN1Z2dlc3RlZFByZXNlbnRhdGlvbkRlbGF5XCIpJiYoYj1hLnN1Z2dlc3RlZFByZXNlbnRhdGlvbkRlbGF5KSxRLndoZW4oYil9LGdldExpdmVTdGFydDpmdW5jdGlvbihhLGIpe3ZhciBjLGQsZT0wLGY9MSxnPTEsaD1udWxsLGk9bnVsbDtyZXR1cm4gZD1hLlBlcmlvZF9hc0FycmF5W2JdLkFkYXB0YXRpb25TZXRfYXNBcnJheVsxXS5SZXByZXNlbnRhdGlvbl9hc0FycmF5WzBdLGQuaGFzT3duUHJvcGVydHkoXCJTZWdtZW50TGlzdFwiKT8oaD1kLlNlZ21lbnRMaXN0LGguaGFzT3duUHJvcGVydHkoXCJzdGFydE51bWJlclwiKSYmKGY9TWF0aC5tYXgoaC5zdGFydE51bWJlciwxKSksaC5oYXNPd25Qcm9wZXJ0eShcInRpbWVzY2FsZVwiKSYmKGc9aC50aW1lc2NhbGUpLGM9aC5kdXJhdGlvbixlPShmLTEpKmMvZyk6ZC5oYXNPd25Qcm9wZXJ0eShcIlNlZ21lbnRUZW1wbGF0ZVwiKSYmKGk9ZC5TZWdtZW50VGVtcGxhdGUsaS5oYXNPd25Qcm9wZXJ0eShcInN0YXJ0TnVtYmVyXCIpJiYoZj1NYXRoLm1heChpLnN0YXJ0TnVtYmVyLDEpKSxpLmhhc093blByb3BlcnR5KFwidGltZXNjYWxlXCIpJiYoZz1pLnRpbWVzY2FsZSksYz1pLmR1cmF0aW9uLGU9aS5oYXNPd25Qcm9wZXJ0eShcIlNlZ21lbnRUaW1lbGluZVwiKT9pLlNlZ21lbnRUaW1lbGluZS5TX2FzQXJyYXlbMF0udC9nOihmLTEpKmMvZyksUS53aGVuKGUpfSxnZXRMaXZlRWRnZTpmdW5jdGlvbihhLGIpe1widXNlIHN0cmljdFwiO3ZhciBjLGQ9dGhpcyxlPVEuZGVmZXIoKSxmPTAsZz1uZXcgRGF0ZSxoPWEuYXZhaWxhYmlsaXR5U3RhcnRUaW1lO3JldHVybiBkLmdldExpdmVPZmZzZXQoYSkudGhlbihmdW5jdGlvbihpKXthLmhhc093blByb3BlcnR5KFwiYXZhaWxhYmlsaXR5RW5kVGltZVwiKT8oYz1hLmF2YWlsYWJpbGl0eUVuZFRpbWUsZj0oYy5nZXRUaW1lKCktaC5nZXRUaW1lKCkpLzFlMyk6Zj0oZy5nZXRUaW1lKCktaC5nZXRUaW1lKCkpLzFlMyxkLmdldExpdmVTdGFydChhLGIpLnRoZW4oZnVuY3Rpb24oYSl7Zis9YSxmLT1pLGUucmVzb2x2ZShmKX0pfSksZS5wcm9taXNlfSxnZXRQcmVzZW50YXRpb25PZmZzZXQ6ZnVuY3Rpb24oYSxiKXt2YXIgYyxkLGU9dGhpcyxmPVEuZGVmZXIoKSxnPTAsaD0xO3JldHVybiBlLmdldFJlcHJlc2VudGF0aW9uRm9yKGEsYikudGhlbihmdW5jdGlvbihhKXtkPWUuZ2V0U2VnbWVudEluZm9Gb3IoYSksbnVsbCE9PWQmJnZvaWQgMCE9PWQmJmQuaGFzT3duUHJvcGVydHkoXCJwcmVzZW50YXRpb25UaW1lT2Zmc2V0XCIpJiYoYz1kLnByZXNlbnRhdGlvblRpbWVPZmZzZXQsZC5oYXNPd25Qcm9wZXJ0eShcInRpbWVzY2FsZVwiKSYmKGg9ZC50aW1lc2NhbGUpLGc9Yy9oKSxmLnJlc29sdmUoZyl9KSxmLnByb21pc2V9LGdldElzTGl2ZTpmdW5jdGlvbihhKXtcInVzZSBzdHJpY3RcIjt2YXIgYj0hMSxjPVwiZHluYW1pY1wiO3JldHVybiBhLmhhc093blByb3BlcnR5KFwidHlwZVwiKSYmKGI9YS50eXBlPT09YyksYn0sZ2V0SXNEVlI6ZnVuY3Rpb24oYSxiKXtcInVzZSBzdHJpY3RcIjt2YXIgYyxkO3JldHVybiBjPSFpc05hTihhLnRpbWVTaGlmdEJ1ZmZlckRlcHRoKSxkPWImJmMsUS53aGVuKGQpfSxnZXRJc09uRGVtYW5kOmZ1bmN0aW9uKGEpe1widXNlIHN0cmljdFwiO3ZhciBiPSExO3JldHVybiBhLnByb2ZpbGVzJiZhLnByb2ZpbGVzLmxlbmd0aD4wJiYoYj0tMSE9PWEucHJvZmlsZXMuaW5kZXhPZihcInVybjptcGVnOmRhc2g6cHJvZmlsZTppc29mZi1vbi1kZW1hbmQ6MjAxMVwiKSksUS53aGVuKGIpfSxnZXREdXJhdGlvbjpmdW5jdGlvbihhLGIpe1widXNlIHN0cmljdFwiO3ZhciBjPTAvMDtyZXR1cm4gYj9jPU51bWJlci5QT1NJVElWRV9JTkZJTklUWTphLm1lZGlhUHJlc2VudGF0aW9uRHVyYXRpb24/Yz1hLm1lZGlhUHJlc2VudGF0aW9uRHVyYXRpb246YS5hdmFpbGFiaWxpdHlFbmRUaW1lJiZhLmF2YWlsYWJpbGl0eVN0YXJ0VGltZSYmKGM9YS5hdmFpbGFiaWxpdHlFbmRUaW1lLmdldFRpbWUoKS1hLmF2YWlsYWJpbGl0eVN0YXJ0VGltZS5nZXRUaW1lKCkpLFEud2hlbihjKX0sZ2V0RHVyYXRpb25Gb3JQZXJpb2Q6ZnVuY3Rpb24oYSxiLGMpe1widXNlIHN0cmljdFwiO3ZhciBkPTAvMDtyZXR1cm4gYz9kPU51bWJlci5QT1NJVElWRV9JTkZJTklUWTpiLlBlcmlvZF9hc0FycmF5Lmxlbmd0aD4xJiZ2b2lkIDAhPT1iLlBlcmlvZF9hc0FycmF5W2FdLmR1cmF0aW9uP2Q9Yi5QZXJpb2RfYXNBcnJheVthXS5kdXJhdGlvbjpiLm1lZGlhUHJlc2VudGF0aW9uRHVyYXRpb24/ZD1iLm1lZGlhUHJlc2VudGF0aW9uRHVyYXRpb246Yi5hdmFpbGFiaWxpdHlFbmRUaW1lJiZiLmF2YWlsYWJpbGl0eVN0YXJ0VGltZSYmKGQ9Yi5hdmFpbGFiaWxpdHlFbmRUaW1lLmdldFRpbWUoKS1iLmF2YWlsYWJpbGl0eVN0YXJ0VGltZS5nZXRUaW1lKCkpLFEud2hlbihkKX0sZ2V0QmFuZHdpZHRoOmZ1bmN0aW9uKGEpe1widXNlIHN0cmljdFwiO3JldHVybiBRLndoZW4oYS5iYW5kd2lkdGgpfSxnZXRSZWZyZXNoRGVsYXk6ZnVuY3Rpb24oYSl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGI9MC8wO3JldHVybiBhLmhhc093blByb3BlcnR5KFwibWluaW11bVVwZGF0ZVBlcmlvZFwiKSYmKGI9cGFyc2VGbG9hdChhLm1pbmltdW1VcGRhdGVQZXJpb2QpKSxRLndoZW4oYil9LGdldFJlcHJlc2VudGF0aW9uQ291bnQ6ZnVuY3Rpb24oYSl7XCJ1c2Ugc3RyaWN0XCI7cmV0dXJuIFEud2hlbihhLlJlcHJlc2VudGF0aW9uX2FzQXJyYXkubGVuZ3RoKX0sZ2V0UmVwcmVzZW50YXRpb25Gb3I6ZnVuY3Rpb24oYSxiKXtcInVzZSBzdHJpY3RcIjtyZXR1cm4gUS53aGVuKGIuUmVwcmVzZW50YXRpb25fYXNBcnJheVthXSl9LGdldFBlcmlvZENvdW50OmZ1bmN0aW9uKGEpe1widXNlIHN0cmljdFwiO3JldHVybiBRLndoZW4oYS5QZXJpb2RfYXNBcnJheS5sZW5ndGgpfSxnZXRUaW1lc3RhbXBPZmZzZXRGb3JQZXJpb2Q6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIGUsZj10aGlzLGc9US5kZWZlcigpO3JldHVybiBmLmdldFByZXNlbnRhdGlvbk9mZnNldChjLGQpLnRoZW4oZnVuY3Rpb24oYyl7Zi5nZXRQZXJpb2RTdGFydChiLGEpLnRoZW4oZnVuY3Rpb24oYSl7ZT1hLWMsZy5yZXNvbHZlKGUpfSl9KSxnLnByb21pc2V9LGdldFBlcmlvZFN0YXJ0OmZ1bmN0aW9uKGEsYil7dmFyIGMsZCxlPXRoaXMsZj1lLmdldElzTGl2ZShhKSxnPW51bGwsaD1udWxsLGk9bnVsbDtmb3IoYz0wO2I+PWM7Yys9MSlnPWEuUGVyaW9kX2FzQXJyYXlbY10sZy5oYXNPd25Qcm9wZXJ0eShcInN0YXJ0XCIpP2Q9Zy5zdGFydDpudWxsIT09aCYmbnVsbCE9PWk/ZD1oK2k6MCE9PWN8fGZ8fChkPTApLGcuaGFzT3duUHJvcGVydHkoXCJkdXJhdGlvblwiKSYmKGk9Zy5kdXJhdGlvbiksaD1kO3JldHVybiBRLndoZW4oZCl9fSxEYXNoLmRlcGVuZGVuY2llcy5EYXNoTWV0cmljc0V4dGVuc2lvbnM9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt2YXIgYT1mdW5jdGlvbihhLGIpe3ZhciBjLGQsZSxmLGcsaCxpLGo7Zm9yKGg9MDtoPGEubGVuZ3RoO2grPTEpZm9yKGM9YVtoXSxlPWMuQWRhcHRhdGlvblNldF9hc0FycmF5LGk9MDtpPGUubGVuZ3RoO2krPTEpZm9yKGQ9ZVtpXSxnPWQuUmVwcmVzZW50YXRpb25fYXNBcnJheSxqPTA7ajxnLmxlbmd0aDtqKz0xKWlmKGY9Z1tqXSxiPT09Zi5pZClyZXR1cm4gajtyZXR1cm4tMX0sYj1mdW5jdGlvbihhLGIpe3ZhciBjLGQsZSxmLGcsaCxpLGo7Zm9yKGg9MDtoPGEubGVuZ3RoO2grPTEpZm9yKGM9YVtoXSxlPWMuQWRhcHRhdGlvblNldF9hc0FycmF5LGk9MDtpPGUubGVuZ3RoO2krPTEpZm9yKGQ9ZVtpXSxnPWQuUmVwcmVzZW50YXRpb25fYXNBcnJheSxqPTA7ajxnLmxlbmd0aDtqKz0xKWlmKGY9Z1tqXSxiPT09Zi5pZClyZXR1cm4gZjtyZXR1cm4gbnVsbH0sYz1mdW5jdGlvbihhLGIpe3ZhciBjPSExO3JldHVyblwidmlkZW9cIj09PWI/KHRoaXMubWFuaWZlc3RFeHQuZ2V0SXNWaWRlbyhhKSxcInZpZGVvXCI9PT1hLnR5cGUmJihjPSEwKSk6XCJhdWRpb1wiPT09Yj8odGhpcy5tYW5pZmVzdEV4dC5nZXRJc0F1ZGlvKGEpLFwiYXVkaW9cIj09PWEudHlwZSYmKGM9ITApKTpjPSExLGN9LGQ9ZnVuY3Rpb24oYSxiKXt2YXIgZCxlLGYsZyxoLGk7Zm9yKGg9MDtoPGEubGVuZ3RoO2grPTEpZm9yKGQ9YVtoXSxmPWQuQWRhcHRhdGlvblNldF9hc0FycmF5LGk9MDtpPGYubGVuZ3RoO2krPTEpaWYoZT1mW2ldLGc9ZS5SZXByZXNlbnRhdGlvbl9hc0FycmF5LGMuY2FsbCh0aGlzLGUsYikpcmV0dXJuIGcubGVuZ3RoO3JldHVybi0xfSxlPWZ1bmN0aW9uKGEpe3ZhciBjLGQ9dGhpcyxlPWQubWFuaWZlc3RNb2RlbC5nZXRWYWx1ZSgpLGY9ZS5QZXJpb2RfYXNBcnJheTtyZXR1cm4gYz1iLmNhbGwoZCxmLGEpLG51bGw9PT1jP251bGw6Yy5iYW5kd2lkdGh9LGY9ZnVuY3Rpb24oYil7dmFyIGMsZD10aGlzLGU9ZC5tYW5pZmVzdE1vZGVsLmdldFZhbHVlKCksZj1lLlBlcmlvZF9hc0FycmF5O3JldHVybiBjPWEuY2FsbChkLGYsYil9LGc9ZnVuY3Rpb24oYSl7dmFyIGIsYz10aGlzLGU9Yy5tYW5pZmVzdE1vZGVsLmdldFZhbHVlKCksZj1lLlBlcmlvZF9hc0FycmF5O3JldHVybiBiPWQuY2FsbCh0aGlzLGYsYSl9LGg9ZnVuY3Rpb24oYSl7aWYobnVsbD09PWEpcmV0dXJuIG51bGw7dmFyIGIsYyxkLGU9YS5SZXBTd2l0Y2hMaXN0O3JldHVybiBudWxsPT09ZXx8ZS5sZW5ndGg8PTA/bnVsbDooYj1lLmxlbmd0aCxjPWItMSxkPWVbY10pfSxpPWZ1bmN0aW9uKGEpe2lmKG51bGw9PT1hKXJldHVybiBudWxsO3ZhciBiLGMsZCxlPWEuQnVmZmVyTGV2ZWw7cmV0dXJuIG51bGw9PT1lfHxlLmxlbmd0aDw9MD9udWxsOihiPWUubGVuZ3RoLGM9Yi0xLGQ9ZVtjXSl9LGo9ZnVuY3Rpb24oYSl7aWYobnVsbD09PWEpcmV0dXJuIG51bGw7dmFyIGIsYyxkLGU9YS5IdHRwTGlzdDtyZXR1cm4gbnVsbD09PWV8fGUubGVuZ3RoPD0wP251bGw6KGI9ZS5sZW5ndGgsYz1iLTEsZD1lW2NdKX0saz1mdW5jdGlvbihhKXtpZihudWxsPT09YSlyZXR1cm4gbnVsbDt2YXIgYixjLGQsZT1hLkRyb3BwZWRGcmFtZXM7cmV0dXJuIG51bGw9PT1lfHxlLmxlbmd0aDw9MD9udWxsOihiPWUubGVuZ3RoLGM9Yi0xLGQ9ZVtjXSl9O3JldHVybnttYW5pZmVzdE1vZGVsOnZvaWQgMCxtYW5pZmVzdEV4dDp2b2lkIDAsZ2V0QmFuZHdpZHRoRm9yUmVwcmVzZW50YXRpb246ZSxnZXRJbmRleEZvclJlcHJlc2VudGF0aW9uOmYsZ2V0TWF4SW5kZXhGb3JCdWZmZXJUeXBlOmcsZ2V0Q3VycmVudFJlcHJlc2VudGF0aW9uU3dpdGNoOmgsZ2V0Q3VycmVudEJ1ZmZlckxldmVsOmksZ2V0Q3VycmVudEh0dHBSZXF1ZXN0OmosZ2V0Q3VycmVudERyb3BwZWRGcmFtZXM6a319LERhc2guZGVwZW5kZW5jaWVzLkRhc2hNZXRyaWNzRXh0ZW5zaW9ucy5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOkRhc2guZGVwZW5kZW5jaWVzLkRhc2hNZXRyaWNzRXh0ZW5zaW9uc30sRGFzaC5kZXBlbmRlbmNpZXMuRGFzaFBhcnNlcj1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3ZhciBhPTMxNTM2ZTMsYj0yNTkyZTMsYz04NjQwMCxkPTM2MDAsZT02MCxmPS9eUCgoW1xcZC5dKilZKT8oKFtcXGQuXSopTSk/KChbXFxkLl0qKUQpP1QoKFtcXGQuXSopSCk/KChbXFxkLl0qKU0pPygoW1xcZC5dKilTKT8vLGc9L14oXFxkezR9XFwtXFxkXFxkXFwtXFxkXFxkKFt0VF1bXFxkOlxcLl0qKT8pKFt6Wl18KFsrXFwtXSkoXFxkXFxkKTooXFxkXFxkKSk/JC8saD0vXlstK10/WzAtOV0rWy5dP1swLTldKihbZUVdWy0rXT9bMC05XSspPyQvLGk9W3t0eXBlOlwiZHVyYXRpb25cIix0ZXN0OmZ1bmN0aW9uKGEpe3JldHVybiBmLnRlc3QoYSl9LGNvbnZlcnRlcjpmdW5jdGlvbihnKXt2YXIgaD1mLmV4ZWMoZyk7cmV0dXJuIHBhcnNlRmxvYXQoaFsyXXx8MCkqYStwYXJzZUZsb2F0KGhbNF18fDApKmIrcGFyc2VGbG9hdChoWzZdfHwwKSpjK3BhcnNlRmxvYXQoaFs4XXx8MCkqZCtwYXJzZUZsb2F0KGhbMTBdfHwwKSplK3BhcnNlRmxvYXQoaFsxMl18fDApfX0se3R5cGU6XCJkYXRldGltZVwiLHRlc3Q6ZnVuY3Rpb24oYSl7cmV0dXJuIGcudGVzdChhKX0sY29udmVydGVyOmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgRGF0ZShhKX19LHt0eXBlOlwibnVtZXJpY1wiLHRlc3Q6ZnVuY3Rpb24oYSl7cmV0dXJuIGgudGVzdChhKX0sY29udmVydGVyOmZ1bmN0aW9uKGEpe3JldHVybiBwYXJzZUZsb2F0KGEpfX1dLGo9ZnVuY3Rpb24oKXt2YXIgYSxiLGMsZDtyZXR1cm4gZD1be25hbWU6XCJwcm9maWxlc1wiLG1lcmdlOiExfSx7bmFtZTpcIndpZHRoXCIsbWVyZ2U6ITF9LHtuYW1lOlwiaGVpZ2h0XCIsbWVyZ2U6ITF9LHtuYW1lOlwic2FyXCIsbWVyZ2U6ITF9LHtuYW1lOlwiZnJhbWVSYXRlXCIsbWVyZ2U6ITF9LHtuYW1lOlwiYXVkaW9TYW1wbGluZ1JhdGVcIixtZXJnZTohMX0se25hbWU6XCJtaW1lVHlwZVwiLG1lcmdlOiExfSx7bmFtZTpcInNlZ21lbnRQcm9maWxlc1wiLG1lcmdlOiExfSx7bmFtZTpcImNvZGVjc1wiLG1lcmdlOiExfSx7bmFtZTpcIm1heGltdW1TQVBQZXJpb2RcIixtZXJnZTohMX0se25hbWU6XCJzdGFydHNXaXRoU2FwXCIsbWVyZ2U6ITF9LHtuYW1lOlwibWF4UGxheW91dFJhdGVcIixtZXJnZTohMX0se25hbWU6XCJjb2RpbmdEZXBlbmRlbmN5XCIsbWVyZ2U6ITF9LHtuYW1lOlwic2NhblR5cGVcIixtZXJnZTohMX0se25hbWU6XCJGcmFtZVBhY2tpbmdcIixtZXJnZTohMH0se25hbWU6XCJBdWRpb0NoYW5uZWxDb25maWd1cmF0aW9uXCIsbWVyZ2U6ITB9LHtuYW1lOlwiQ29udGVudFByb3RlY3Rpb25cIixtZXJnZTohMH1dLGE9e30sYS5uYW1lPVwiQWRhcHRhdGlvblNldFwiLGEuaXNSb290PSExLGEuaXNBcnJheT0hMCxhLnBhcmVudD1udWxsLGEuY2hpbGRyZW49W10sYS5wcm9wZXJ0aWVzPWQsYj17fSxiLm5hbWU9XCJSZXByZXNlbnRhdGlvblwiLGIuaXNSb290PSExLGIuaXNBcnJheT0hMCxiLnBhcmVudD1hLGIuY2hpbGRyZW49W10sYi5wcm9wZXJ0aWVzPWQsYS5jaGlsZHJlbi5wdXNoKGIpLGM9e30sYy5uYW1lPVwiU3ViUmVwcmVzZW50YXRpb25cIixjLmlzUm9vdD0hMSxjLmlzQXJyYXk9ITAsYy5wYXJlbnQ9YixjLmNoaWxkcmVuPVtdLGMucHJvcGVydGllcz1kLGIuY2hpbGRyZW4ucHVzaChjKSxhfSxrPWZ1bmN0aW9uKCl7dmFyIGEsYixjLGQ7cmV0dXJuIGQ9W3tuYW1lOlwiU2VnbWVudEJhc2VcIixtZXJnZTohMH0se25hbWU6XCJTZWdtZW50VGVtcGxhdGVcIixtZXJnZTohMH0se25hbWU6XCJTZWdtZW50TGlzdFwiLG1lcmdlOiEwfV0sYT17fSxhLm5hbWU9XCJQZXJpb2RcIixhLmlzUm9vdD0hMSxhLmlzQXJyYXk9ITAsYS5wYXJlbnQ9bnVsbCxhLmNoaWxkcmVuPVtdLGEucHJvcGVydGllcz1kLGI9e30sYi5uYW1lPVwiQWRhcHRhdGlvblNldFwiLGIuaXNSb290PSExLGIuaXNBcnJheT0hMCxiLnBhcmVudD1hLGIuY2hpbGRyZW49W10sYi5wcm9wZXJ0aWVzPWQsYS5jaGlsZHJlbi5wdXNoKGIpLGM9e30sYy5uYW1lPVwiUmVwcmVzZW50YXRpb25cIixjLmlzUm9vdD0hMSxjLmlzQXJyYXk9ITAsYy5wYXJlbnQ9YixjLmNoaWxkcmVuPVtdLGMucHJvcGVydGllcz1kLGIuY2hpbGRyZW4ucHVzaChjKSxhfSxsPWZ1bmN0aW9uKCl7dmFyIGEsYixjLGQsZTtyZXR1cm4gZT1be25hbWU6XCJCYXNlVVJMXCIsbWVyZ2U6ITAsbWVyZ2VGdW5jdGlvbjpmdW5jdGlvbihhLGIpe3ZhciBjO3JldHVybiBjPTA9PT1iLmluZGV4T2YoXCJodHRwOi8vXCIpP2I6YStifX1dLGE9e30sYS5uYW1lPVwibXBkXCIsYS5pc1Jvb3Q9ITAsYS5pc0FycmF5PSEwLGEucGFyZW50PW51bGwsYS5jaGlsZHJlbj1bXSxhLnByb3BlcnRpZXM9ZSxiPXt9LGIubmFtZT1cIlBlcmlvZFwiLGIuaXNSb290PSExLGIuaXNBcnJheT0hMCxiLnBhcmVudD1udWxsLGIuY2hpbGRyZW49W10sYi5wcm9wZXJ0aWVzPWUsYS5jaGlsZHJlbi5wdXNoKGIpLGM9e30sYy5uYW1lPVwiQWRhcHRhdGlvblNldFwiLGMuaXNSb290PSExLGMuaXNBcnJheT0hMCxjLnBhcmVudD1iLGMuY2hpbGRyZW49W10sYy5wcm9wZXJ0aWVzPWUsYi5jaGlsZHJlbi5wdXNoKGMpLGQ9e30sZC5uYW1lPVwiUmVwcmVzZW50YXRpb25cIixkLmlzUm9vdD0hMSxkLmlzQXJyYXk9ITAsZC5wYXJlbnQ9YyxkLmNoaWxkcmVuPVtdLGQucHJvcGVydGllcz1lLGMuY2hpbGRyZW4ucHVzaChkKSxhfSxtPWZ1bmN0aW9uKCl7dmFyIGE9W107cmV0dXJuIGEucHVzaChqKCkpLGEucHVzaChrKCkpLGEucHVzaChsKCkpLGF9LG49ZnVuY3Rpb24oYSxiKXt0aGlzLmRlYnVnLmxvZyhcIkRvaW5nIHBhcnNlLlwiKTt2YXIgYyxkPW5ldyBYMkpTKGksXCJcIiwhMCksZT1uZXcgT2JqZWN0SXJvbihtKCkpO3RyeXt0aGlzLmRlYnVnLmxvZyhcIkNvbnZlcnRpbmcgZnJvbSBYTUwuXCIpLGM9ZC54bWxfc3RyMmpzb24oYSksYy5oYXNPd25Qcm9wZXJ0eShcIkJhc2VVUkxcIik/KGMuQmFzZVVSTD1jLkJhc2VVUkxfYXNBcnJheVswXSwwIT09Yy5CYXNlVVJMLnRvU3RyaW5nKCkuaW5kZXhPZihcImh0dHBcIikmJihjLkJhc2VVUkw9YitjLkJhc2VVUkwpKToodGhpcy5kZWJ1Zy5sb2coXCJTZXR0aW5nIGJhc2VVUkw6IFwiK2IpLGMuQmFzZVVSTD1iKSx0aGlzLmRlYnVnLmxvZyhcIkZsYXR0ZW4gbWFuaWZlc3QgcHJvcGVydGllcy5cIiksZS5ydW4oYyksdGhpcy5kZWJ1Zy5sb2coXCJQYXJzaW5nIGNvbXBsZXRlLlwiKX1jYXRjaChmKXtyZXR1cm4gdGhpcy5lcnJIYW5kbGVyLm1hbmlmZXN0RXJyb3IoXCJwYXJzaW5nIHRoZSBtYW5pZmVzdCBmYWlsZWRcIixcInBhcnNlXCIsYSksUS5yZWplY3QoZil9cmV0dXJuIFEud2hlbihjKX07cmV0dXJue2RlYnVnOnZvaWQgMCxlcnJIYW5kbGVyOnZvaWQgMCxwYXJzZTpufX0sRGFzaC5kZXBlbmRlbmNpZXMuRGFzaFBhcnNlci5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOkRhc2guZGVwZW5kZW5jaWVzLkRhc2hQYXJzZXJ9LERhc2guZGVwZW5kZW5jaWVzLkZyYWdtZW50RXh0ZW5zaW9ucz1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3ZhciBhPWZ1bmN0aW9uKGEpe2Zvcih2YXIgYixjLGQsZSxmLGcsaD1RLmRlZmVyKCksaT1uZXcgRGF0YVZpZXcoYSksaj0wO1widGZkdFwiIT09ZSYmajxpLmJ5dGVMZW5ndGg7KXtmb3IoZD1pLmdldFVpbnQzMihqKSxqKz00LGU9XCJcIixmPTA7ND5mO2YrPTEpZz1pLmdldEludDgoaiksZSs9U3RyaW5nLmZyb21DaGFyQ29kZShnKSxqKz0xO1wibW9vZlwiIT09ZSYmXCJ0cmFmXCIhPT1lJiZcInRmZHRcIiE9PWUmJihqKz1kLTgpfWlmKGo9PT1pLmJ5dGVMZW5ndGgpdGhyb3dcIkVycm9yIGZpbmRpbmcgbGl2ZSBvZmZzZXQuXCI7cmV0dXJuIGM9aS5nZXRVaW50OChqKSx0aGlzLmRlYnVnLmxvZyhcInBvc2l0aW9uOiBcIitqKSwwPT09Yz8oais9NCxiPWkuZ2V0VWludDMyKGosITEpKTooais9ZC0xNixiPXV0aWxzLk1hdGgudG82NEJpdE51bWJlcihpLmdldFVpbnQzMihqKzQsITEpLGkuZ2V0VWludDMyKGosITEpKSksaC5yZXNvbHZlKHt2ZXJzaW9uOmMsYmFzZV9tZWRpYV9kZWNvZGVfdGltZTpifSksaC5wcm9taXNlfSxiPWZ1bmN0aW9uKGEpe2Zvcih2YXIgYixjLGQsZSxmLGcsaCxpPW5ldyBEYXRhVmlldyhhKSxqPTA7XCJzaWR4XCIhPT1mJiZqPGkuYnl0ZUxlbmd0aDspe2ZvcihnPWkuZ2V0VWludDMyKGopLGorPTQsZj1cIlwiLGU9MDs0PmU7ZSs9MSloPWkuZ2V0SW50OChqKSxmKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGgpLGorPTE7XCJtb29mXCIhPT1mJiZcInRyYWZcIiE9PWYmJlwic2lkeFwiIT09Zj9qKz1nLTg6XCJzaWR4XCI9PT1mJiYoai09OCl9cmV0dXJuIGI9aS5nZXRVaW50OChqKzgpLGorPTEyLGM9aS5nZXRVaW50MzIoais0LCExKSxqKz04LGQ9MD09PWI/aS5nZXRVaW50MzIoaiwhMSk6dXRpbHMuTWF0aC50bzY0Qml0TnVtYmVyKGkuZ2V0VWludDMyKGorNCwhMSksaS5nZXRVaW50MzIoaiwhMSkpLFEud2hlbih7ZWFybGllc3RQcmVzZW50YXRpb25UaW1lOmQsdGltZXNjYWxlOmN9KX0sYz1mdW5jdGlvbihiKXt2YXIgYyxkLGUsZj1RLmRlZmVyKCksZz1uZXcgWE1MSHR0cFJlcXVlc3QsaD0hMTtyZXR1cm4gYz1iLGcub25sb2FkZW5kPWZ1bmN0aW9uKCl7aHx8KGQ9XCJFcnJvciBsb2FkaW5nIGZyYWdtZW50OiBcIitjLGYucmVqZWN0KGQpKX0sZy5vbmxvYWQ9ZnVuY3Rpb24oKXtoPSEwLGU9YShnLnJlc3BvbnNlKSxmLnJlc29sdmUoZSl9LGcub25lcnJvcj1mdW5jdGlvbigpe2Q9XCJFcnJvciBsb2FkaW5nIGZyYWdtZW50OiBcIitjLGYucmVqZWN0KGQpfSxnLnJlc3BvbnNlVHlwZT1cImFycmF5YnVmZmVyXCIsZy5vcGVuKFwiR0VUXCIsYyksZy5zZW5kKG51bGwpLGYucHJvbWlzZX07cmV0dXJue2RlYnVnOnZvaWQgMCxsb2FkRnJhZ21lbnQ6YyxwYXJzZVRGRFQ6YSxwYXJzZVNJRFg6Yn19LERhc2guZGVwZW5kZW5jaWVzLkZyYWdtZW50RXh0ZW5zaW9ucy5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOkRhc2guZGVwZW5kZW5jaWVzLkZyYWdtZW50RXh0ZW5zaW9uc30sRGFzaC52by5TZWdtZW50PWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7dGhpcy5pbmRleFJhbmdlPW51bGwsdGhpcy5pbmRleD1udWxsLHRoaXMubWVkaWFSYW5nZT1udWxsLHRoaXMubWVkaWE9bnVsbCx0aGlzLmR1cmF0aW9uPTAvMCx0aGlzLnN0YXJ0VGltZT0wLzAsdGhpcy50aW1lc2NhbGU9MC8wfSxEYXNoLnZvLlNlZ21lbnQucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpEYXNoLnZvLlNlZ21lbnR9LE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5BYnJDb250cm9sbGVyPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGE9ITAsYj17fSxjPXt9LGQ9ZnVuY3Rpb24oYSl7dmFyIGM7cmV0dXJuIGIuaGFzT3duUHJvcGVydHkoYSl8fChiW2FdPTApLGM9YlthXX0sZT1mdW5jdGlvbihhLGMpe2JbYV09Y30sZj1mdW5jdGlvbihhKXt2YXIgYjtyZXR1cm4gYy5oYXNPd25Qcm9wZXJ0eShhKXx8KGNbYV09MCksYj1jW2FdfSxnPWZ1bmN0aW9uKGEsYil7Y1thXT1ifTtyZXR1cm57ZGVidWc6dm9pZCAwLGFiclJ1bGVzQ29sbGVjdGlvbjp2b2lkIDAsbWFuaWZlc3RFeHQ6dm9pZCAwLG1ldHJpY3NNb2RlbDp2b2lkIDAsZ2V0QXV0b1N3aXRjaEJpdHJhdGU6ZnVuY3Rpb24oKXtyZXR1cm4gYX0sc2V0QXV0b1N3aXRjaEJpdHJhdGU6ZnVuY3Rpb24oYil7YT1ifSxnZXRNZXRyaWNzRm9yOmZ1bmN0aW9uKGEpe3ZhciBiPVEuZGVmZXIoKSxjPXRoaXM7cmV0dXJuIGMubWFuaWZlc3RFeHQuZ2V0SXNWaWRlbyhhKS50aGVuKGZ1bmN0aW9uKGQpe2Q/Yi5yZXNvbHZlKGMubWV0cmljc01vZGVsLmdldE1ldHJpY3NGb3IoXCJ2aWRlb1wiKSk6Yy5tYW5pZmVzdEV4dC5nZXRJc0F1ZGlvKGEpLnRoZW4oZnVuY3Rpb24oYSl7YT9iLnJlc29sdmUoYy5tZXRyaWNzTW9kZWwuZ2V0TWV0cmljc0ZvcihcImF1ZGlvXCIpKTpiLnJlc29sdmUoYy5tZXRyaWNzTW9kZWwuZ2V0TWV0cmljc0ZvcihcInN0cmVhbVwiKSl9KX0pLGIucHJvbWlzZX0sZ2V0UGxheWJhY2tRdWFsaXR5OmZ1bmN0aW9uKGIsYyl7dmFyIGgsaSxqLGssbCxtLG49dGhpcyxvPVEuZGVmZXIoKSxwPU1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlLk5PX0NIQU5HRSxxPU1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlLk5PX0NIQU5HRSxyPVtdO3JldHVybiBsPWQoYiksbT1mKGIpLG4uZGVidWcubG9nKFwiQUJSIGVuYWJsZWQ/IChcIithK1wiKVwiKSxhPyhuLmRlYnVnLmxvZyhcIkNoZWNrIEFCUiBydWxlcy5cIiksbi5nZXRNZXRyaWNzRm9yKGMpLnRoZW4oZnVuY3Rpb24oYSl7bi5hYnJSdWxlc0NvbGxlY3Rpb24uZ2V0UnVsZXMoKS50aGVuKGZ1bmN0aW9uKGQpe2ZvcihoPTAsaT1kLmxlbmd0aDtpPmg7aCs9MSlyLnB1c2goZFtoXS5jaGVja0luZGV4KGwsYSxjKSk7XHJcblEuYWxsKHIpLnRoZW4oZnVuY3Rpb24oYSl7Zm9yKG4uZGVidWcubG9nKGEpLGs9e30sa1tNZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0LnByb3RvdHlwZS5TVFJPTkddPU1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlLk5PX0NIQU5HRSxrW01lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlLldFQUtdPU1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlLk5PX0NIQU5HRSxrW01lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlLkRFRkFVTFRdPU1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlLk5PX0NIQU5HRSxoPTAsaT1hLmxlbmd0aDtpPmg7aCs9MSlqPWFbaF0sai5xdWFsaXR5IT09TWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdC5wcm90b3R5cGUuTk9fQ0hBTkdFJiYoa1tqLnByaW9yaXR5XT1NYXRoLm1pbihrW2oucHJpb3JpdHldLGoucXVhbGl0eSkpO2tbTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdC5wcm90b3R5cGUuV0VBS10hPT1NZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0LnByb3RvdHlwZS5OT19DSEFOR0UmJihxPU1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlLldFQUsscD1rW01lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlLldFQUtdKSxrW01lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlLkRFRkFVTFRdIT09TWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdC5wcm90b3R5cGUuTk9fQ0hBTkdFJiYocT1NZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0LnByb3RvdHlwZS5ERUZBVUxULHA9a1tNZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0LnByb3RvdHlwZS5ERUZBVUxUXSksa1tNZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0LnByb3RvdHlwZS5TVFJPTkddIT09TWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdC5wcm90b3R5cGUuTk9fQ0hBTkdFJiYocT1NZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0LnByb3RvdHlwZS5TVFJPTkcscD1rW01lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlLlNUUk9OR10pLHAhPT1NZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0LnByb3RvdHlwZS5OT19DSEFOR0UmJnZvaWQgMCE9PXAmJihsPXApLHEhPT1NZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0LnByb3RvdHlwZS5OT19DSEFOR0UmJnZvaWQgMCE9PXEmJihtPXEpLG4ubWFuaWZlc3RFeHQuZ2V0UmVwcmVzZW50YXRpb25Db3VudChjKS50aGVuKGZ1bmN0aW9uKGEpezA+bCYmKGw9MCksbD49YSYmKGw9YS0xKSxtIT1NZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0LnByb3RvdHlwZS5TVFJPTkcmJm0hPU1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlLldFQUsmJihtPU1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlLkRFRkFVTFQpLGUoYixsKSxuLmRlYnVnLmxvZyhcIk5ldyBxdWFsaXR5IG9mIFwiK2wpLGcoYixtKSxuLmRlYnVnLmxvZyhcIk5ldyBjb25maWRlbmNlIG9mIFwiK20pLG8ucmVzb2x2ZSh7cXVhbGl0eTpsLGNvbmZpZGVuY2U6bX0pfSl9KX0pfSkpOihuLmRlYnVnLmxvZyhcIlVuY2hhbmdlZCBxdWFsaXR5IG9mIFwiK2wpLG8ucmVzb2x2ZSh7cXVhbGl0eTpsLGNvbmZpZGVuY2U6bX0pKSxvLnByb21pc2V9LHNldFBsYXliYWNrUXVhbGl0eTpmdW5jdGlvbihhLGIpe3ZhciBjPWQoYSk7YiE9PWMmJmUoYSxiKX0sZ2V0UXVhbGl0eUZvcjpmdW5jdGlvbihhKXtyZXR1cm4gZChhKX19fSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuQWJyQ29udHJvbGxlci5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOk1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5BYnJDb250cm9sbGVyfSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuQnVmZmVyQ29udHJvbGxlcj1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3ZhciBhLGIsYyxkLGU9LjUsZj0yMixnPVwiV0FJVElOR1wiLGg9XCJSRUFEWVwiLGk9XCJWQUxJREFUSU5HXCIsaj1cIkxPQURJTkdcIixrPWcsbD0hMSxtPSExLG49ITEsbz0hMCxwPVtdLHE9ITEscj0tMSxzPSEwLHQ9LTEsdT0hMSx2PSExLHc9ITEseD0hMSx5PVtdLHo9bnVsbCxBPVEuZGVmZXIoKSxCPW51bGwsQz1udWxsLEQ9LTEsRT0wLEY9MCxHPW51bGwsSD0wLEk9ITEsSj1udWxsLEs9MCxMPSExLE09bnVsbCxOPW51bGwsTz1udWxsLFA9bnVsbCxSPSEwLFM9ZnVuY3Rpb24oYSl7dmFyIGI9dGhpcztiLmRlYnVnLmxvZyhcIkJ1ZmZlckNvbnRyb2xsZXIgXCIrYytcIiBzZXRTdGF0ZSB0bzpcIithKSxrPWEsbnVsbCE9PUcmJmIuZnJhZ21lbnRDb250cm9sbGVyLm9uQnVmZmVyQ29udHJvbGxlclN0YXRlQ2hhbmdlKCl9LFQ9ZnVuY3Rpb24oYSxiKXt2YXIgYz0wLGQ9bnVsbDtSPT09ITEmJihkPVAuc3RhcnQsYz1hLmdldFRpbWUoKS1kLmdldFRpbWUoKSxQLmR1cmF0aW9uPWMsUC5zdG9wcmVhc29uPWIsUj0hMCl9LFU9ZnVuY3Rpb24oKXt2YXIgYT10aGlzLm1hbmlmZXN0TW9kZWwuZ2V0VmFsdWUoKSxiPXRoaXMubWFuaWZlc3RFeHQuZ2V0SXNMaXZlKGEpO3JldHVybiB3PSEwLFEud2hlbihiKX0sVj1mdW5jdGlvbigpe2lmKGwmJm0pe3ZhciBhPXRoaXM7VS5jYWxsKHRoaXMpLnRoZW4oZnVuY3Rpb24oYil7dj1iLGEuZGVidWcubG9nKFwiQnVmZmVyQ29udHJvbGxlciBiZWdpbiBcIitjK1wiIHZhbGlkYXRpb25cIiksUy5jYWxsKGEsaCksYS5yZXF1ZXN0U2NoZWR1bGVyLnN0YXJ0U2NoZWR1bGluZyhhLHJiKSxHPWEuZnJhZ21lbnRDb250cm9sbGVyLmF0dGFjaEJ1ZmZlckNvbnRyb2xsZXIoYSl9KX19LFc9ZnVuY3Rpb24oKXt2YXIgYTt0aGlzLnJlcXVlc3RTY2hlZHVsZXIuaXNTY2hlZHVsZWQodGhpcyl8fChxPT09ITEmJihhPW5ldyBEYXRlLFQoYSxNZWRpYVBsYXllci52by5tZXRyaWNzLlBsYXlMaXN0LlRyYWNlLlVTRVJfUkVRVUVTVF9TVE9QX1JFQVNPTiksTz10aGlzLm1ldHJpY3NNb2RlbC5hZGRQbGF5TGlzdChjLGEsMCxNZWRpYVBsYXllci52by5tZXRyaWNzLlBsYXlMaXN0LklOSVRJQUxfUExBWV9TVEFSVF9SRUFTT04pKSx0aGlzLmRlYnVnLmxvZyhcIkJ1ZmZlckNvbnRyb2xsZXIgXCIrYytcIiBzdGFydC5cIiksbT0hMCxuPSEwLFYuY2FsbCh0aGlzKSl9LFg9ZnVuY3Rpb24oYSl7dmFyIGI7dGhpcy5kZWJ1Zy5sb2coXCJCdWZmZXJDb250cm9sbGVyIFwiK2MrXCIgc2VlazogXCIrYSkscT0hMCxyPWEsYj1uZXcgRGF0ZSxUKGIsTWVkaWFQbGF5ZXIudm8ubWV0cmljcy5QbGF5TGlzdC5UcmFjZS5VU0VSX1JFUVVFU1RfU1RPUF9SRUFTT04pLE89dGhpcy5tZXRyaWNzTW9kZWwuYWRkUGxheUxpc3QoYyxiLHIsTWVkaWFQbGF5ZXIudm8ubWV0cmljcy5QbGF5TGlzdC5TRUVLX1NUQVJUX1JFQVNPTiksVy5jYWxsKHRoaXMpfSxZPWZ1bmN0aW9uKCl7ayE9PWcmJih0aGlzLmRlYnVnLmxvZyhcIkJ1ZmZlckNvbnRyb2xsZXIgXCIrYytcIiBzdG9wLlwiKSxTLmNhbGwodGhpcyxnKSx0aGlzLnJlcXVlc3RTY2hlZHVsZXIuc3RvcFNjaGVkdWxpbmcodGhpcyksdGhpcy5mcmFnbWVudENvbnRyb2xsZXIuY2FuY2VsUGVuZGluZ1JlcXVlc3RzRm9yTW9kZWwoRyksbT0hMSxuPSExLFQobmV3IERhdGUsTWVkaWFQbGF5ZXIudm8ubWV0cmljcy5QbGF5TGlzdC5UcmFjZS5VU0VSX1JFUVVFU1RfU1RPUF9SRUFTT04pKX0sWj1mdW5jdGlvbihhLGIpe3ZhciBjPW51bGw7cmV0dXJuIGImJmIuUmVwcmVzZW50YXRpb25fYXNBcnJheSYmYi5SZXByZXNlbnRhdGlvbl9hc0FycmF5Lmxlbmd0aD4wJiYoYz1iLlJlcHJlc2VudGF0aW9uX2FzQXJyYXlbYV0pLGN9LCQ9ZnVuY3Rpb24oKXt2YXIgYT10aGlzO2s9PT1qJiYodSYmKHU9ITEsdGhpcy52aWRlb01vZGVsLnN0YWxsU3RyZWFtKGMsdSkpLFMuY2FsbChhLGgpKX0sXz1mdW5jdGlvbihhKXtpZih0aGlzLmZyYWdtZW50Q29udHJvbGxlci5pc0luaXRpYWxpemF0aW9uUmVxdWVzdChhKSlTLmNhbGwodGhpcyxoKTtlbHNle1MuY2FsbCh0aGlzLGopO3ZhciBiPXRoaXMsYz1iLmZyYWdtZW50Q29udHJvbGxlci5nZXRMb2FkaW5nVGltZShiKTtzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7KE18fE4pJiYoUy5jYWxsKGIsaCkscWIuY2FsbChiKSl9LGMpfX0sYWI9ZnVuY3Rpb24oYSxiKXt0aGlzLmZyYWdtZW50Q29udHJvbGxlci5pc0luaXRpYWxpemF0aW9uUmVxdWVzdChhKT9oYi5jYWxsKHRoaXMsYSxiKTpiYi5jYWxsKHRoaXMsYSxiKX0sYmI9ZnVuY3Rpb24oYSxiKXt2YXIgZD10aGlzO2QuZGVidWcubG9nKGMrXCIgQnl0ZXMgZmluaXNoZWQgbG9hZGluZzogXCIrYS51cmwpLEt8fGlzTmFOKGEuZHVyYXRpb24pfHwoSz1hLmR1cmF0aW9uKSxkLmZyYWdtZW50Q29udHJvbGxlci5wcm9jZXNzKGIuZGF0YSkudGhlbihmdW5jdGlvbihiKXtudWxsIT09YiYmbnVsbCE9PXo/US53aGVuKHoucHJvbWlzZSkudGhlbihmdW5jdGlvbigpe2NiLmNhbGwoZCxiLGEucXVhbGl0eSkudGhlbihmdW5jdGlvbigpe0EucHJvbWlzZS50aGVuKGZ1bmN0aW9uKGIpe2IuaW5kZXgtMSE9PWEuaW5kZXh8fHh8fCh4PSEwLHUmJih1PSExLGQudmlkZW9Nb2RlbC5zdGFsbFN0cmVhbShjLHUpKSxTLmNhbGwoZCxoKSxkLnN5c3RlbS5ub3RpZnkoXCJidWZmZXJpbmdDb21wbGV0ZWRcIikpfSl9KX0pOmQuZGVidWcubG9nKFwiTm8gXCIrYytcIiBieXRlcyB0byBwdXNoLlwiKX0pfSxjYj1mdW5jdGlvbihhLGIpe3ZhciBkPXRoaXMsZT1hPT1KLGg9ZT9COlEuZGVmZXIoKSxpPWU/eS5sZW5ndGg6eS5wdXNoKGgpLGo9Wih0LGQuZ2V0RGF0YSgpKSxsPWQudmlkZW9Nb2RlbC5nZXRDdXJyZW50VGltZSgpLG09bmV3IERhdGU7cmV0dXJuIGQuZGVidWcubG9nKFwiUHVzaCAoXCIrYytcIikgYnl0ZXM6IFwiK2EuYnl0ZUxlbmd0aCksUj09PSEwJiZrIT09ZyYmLTEhPT10JiYoUj0hMSxQPWQubWV0cmljc01vZGVsLmFwcGVuZFBsYXlMaXN0VHJhY2UoTyxqLmlkLG51bGwsbSxsLG51bGwsMSxudWxsKSksUS53aGVuKGV8fDI+aXx8eVtpLTJdLnByb21pc2UpLnRoZW4oZnVuY3Rpb24oKXtOJiZmYi5jYWxsKGQpLnRoZW4oZnVuY3Rpb24oKXtyZXR1cm4gYiE9PXQ/KGgucmVzb2x2ZSgpLGUmJihCPW51bGwsSj1udWxsKSx2b2lkIDApOihRLndoZW4oQz9DLnByb21pc2U6ITApLnRoZW4oZnVuY3Rpb24oKXtkLnNvdXJjZUJ1ZmZlckV4dC5hcHBlbmQoTixhLGQudmlkZW9Nb2RlbCkudGhlbihmdW5jdGlvbigpe2UmJihCPW51bGwsSj1udWxsKSxkLnJlcXVlc3RTY2hlZHVsZXIuaXNTY2hlZHVsZWQoZCl8fFcuY2FsbChkKSxJPSExLGRiLmNhbGwoZCkudGhlbihmdW5jdGlvbigpe2gucmVzb2x2ZSgpfSksTiYmZC5zb3VyY2VCdWZmZXJFeHQuZ2V0QWxsUmFuZ2VzKE4pLnRoZW4oZnVuY3Rpb24oYSl7aWYoYSYmKGQuZGVidWcubG9nKFwiQXBwZW5kIFwiK2MrXCIgY29tcGxldGU6IFwiK2EubGVuZ3RoKSxhLmxlbmd0aD4wKSl7dmFyIGIsZTtmb3IoZC5kZWJ1Zy5sb2coXCJOdW1iZXIgb2YgYnVmZmVyZWQgXCIrYytcIiByYW5nZXM6IFwiK2EubGVuZ3RoKSxiPTAsZT1hLmxlbmd0aDtlPmI7Yis9MSlkLmRlYnVnLmxvZyhcIkJ1ZmZlcmVkIFwiK2MrXCIgUmFuZ2U6IFwiK2Euc3RhcnQoYikrXCIgLSBcIithLmVuZChiKSl9fSl9LGZ1bmN0aW9uKGIpe2IuZXJyLmNvZGU9PT1mJiYoSj1hLEI9aCxJPSEwLEY9MCxZLmNhbGwoZCkpfSl9KSx2b2lkIDApfSl9KSxoLnByb21pc2V9LGRiPWZ1bmN0aW9uKCl7aWYoIU0mJiFOKXJldHVybiBRLndoZW4oITEpO3ZhciBhPXRoaXMsYj1RLmRlZmVyKCksZD1vYi5jYWxsKGEpO3JldHVybiBhLnNvdXJjZUJ1ZmZlckV4dC5nZXRCdWZmZXJMZW5ndGgoTixkKS50aGVuKGZ1bmN0aW9uKGQpe0g9ZCxhLm1ldHJpY3NNb2RlbC5hZGRCdWZmZXJMZXZlbChjLG5ldyBEYXRlLEgpLGViLmNhbGwoYSksYi5yZXNvbHZlKCl9KSxiLnByb21pc2V9LGViPWZ1bmN0aW9uKCl7dmFyIGE9dGhpcy5idWZmZXJFeHQuZ2V0TGVhc3RCdWZmZXJMZXZlbCgpLGI9MipLLGM9SC1hO2M+YiYmIUM/KEY9MCxDPVEuZGVmZXIoKSk6Yj5jJiZDJiYoQy5yZXNvbHZlKCksQz1udWxsKX0sZmI9ZnVuY3Rpb24oKXt2YXIgYSxiPXRoaXMsYz1RLmRlZmVyKCksZD0wO3JldHVybiBJPyhhPWZ1bmN0aW9uKCl7Z2IuY2FsbChiKS50aGVuKGZ1bmN0aW9uKGIpe2QrPWIsZD49Sz9jLnJlc29sdmUoKTpzZXRUaW1lb3V0KGEsMWUzKkspfSl9LGEuY2FsbChiKSxjLnByb21pc2UpOlEud2hlbighMCl9LGdiPWZ1bmN0aW9uKCl7dmFyIGEsYyxkPXRoaXMsZT1RLmRlZmVyKCksZj1kLnZpZGVvTW9kZWwuZ2V0Q3VycmVudFRpbWUoKSxnPTA7cmV0dXJuIGM9ZC5mcmFnbWVudENvbnRyb2xsZXIuZ2V0RXhlY3V0ZWRSZXF1ZXN0Rm9yVGltZShHLGYpLGE9YyYmIWlzTmFOKGMuc3RhcnRUaW1lKT9jLnN0YXJ0VGltZTpNYXRoLmZsb29yKGYpLEs9YyYmIWlzTmFOKGMuZHVyYXRpb24pP2MuZHVyYXRpb246MSxkLnNvdXJjZUJ1ZmZlckV4dC5nZXRCdWZmZXJSYW5nZShOLGYpLnRoZW4oZnVuY3Rpb24oYyl7bnVsbD09PWMmJnI9PT1mJiZOLmJ1ZmZlcmVkLmxlbmd0aD4wJiYoYT1OLmJ1ZmZlcmVkLmVuZChOLmJ1ZmZlcmVkLmxlbmd0aC0xKSksZz1OLmJ1ZmZlcmVkLnN0YXJ0KDApLGQuc291cmNlQnVmZmVyRXh0LnJlbW92ZShOLGcsYSxFLGIpLnRoZW4oZnVuY3Rpb24oKXtkLmZyYWdtZW50Q29udHJvbGxlci5yZW1vdmVFeGVjdXRlZFJlcXVlc3RzQmVmb3JlVGltZShHLGEpLGUucmVzb2x2ZShhLWcpfSl9KSxlLnByb21pc2V9LGhiPWZ1bmN0aW9uKGEsYil7dmFyIGQ9dGhpcyxlPWIuZGF0YSxmPWEucXVhbGl0eTtkLmRlYnVnLmxvZyhjK1wiIEluaXRpYWxpemF0aW9uIGZpbmlzaGVkIGxvYWRpbmc6IFwiK2EudXJsKSxkLmZyYWdtZW50Q29udHJvbGxlci5wcm9jZXNzKGUpLnRoZW4oZnVuY3Rpb24oYil7bnVsbCE9PWI/KHBbZl09YixmPT09dCYmY2IuY2FsbChkLGIsYS5xdWFsaXR5KS50aGVuKGZ1bmN0aW9uKCl7ei5yZXNvbHZlKCl9KSk6ZC5kZWJ1Zy5sb2coXCJObyBcIitjK1wiIGJ5dGVzIHRvIHB1c2guXCIpfSl9LGliPWZ1bmN0aW9uKCl7dmFyIGE9dGhpcyxiPWEubWFuaWZlc3RNb2RlbC5nZXRWYWx1ZSgpLGM9YS5tYW5pZmVzdEV4dC5nZXRJc0xpdmUoYik7az09PWomJlMuY2FsbChhLGgpLGN8fGEuc3lzdGVtLm5vdGlmeShcInNlZ21lbnRMb2FkaW5nRmFpbGVkXCIpfSxqYj1mdW5jdGlvbihhKXt0aGlzLmRlYnVnLmxvZyhjK1wiIFN0cmVhbSBpcyBjb21wbGV0ZS5cIiksVChuZXcgRGF0ZSxNZWRpYVBsYXllci52by5tZXRyaWNzLlBsYXlMaXN0LlRyYWNlLkVORF9PRl9DT05URU5UX1NUT1BfUkVBU09OKSxZLmNhbGwodGhpcyksQS5yZXNvbHZlKGEpfSxrYj1mdW5jdGlvbihhLGIpe3ZhciBkLGU9bnVsbCxmPXRoaXMuYnVmZmVyRXh0LmdldFRvcFF1YWxpdHlJbmRleChjKSxnPVtdO2lmKG8mJih0aGlzLmRlYnVnLmxvZyhcIk1hcmtpbmcgYSBzcGVjaWFsIHNlZWsgZm9yIGluaXRpYWwgXCIrYytcIiBwbGF5YmFjay5cIikscXx8KHE9ITAscj0wKSxvPSExKSxzKXtmb3Ioej1RLmRlZmVyKCkscD1bXSxkPTA7Zj49ZDtkKz0xKWcucHVzaCh0aGlzLmluZGV4SGFuZGxlci5nZXRJbml0UmVxdWVzdChkLE0pKTt0PWIsZT1RLmFsbChnKX1lbHNlIGU9US53aGVuKG51bGwpLGEmJih6PVEuZGVmZXIoKSx0PWIscFtiXSYmY2IuY2FsbCh0aGlzLHBbYl0sYikudGhlbihmdW5jdGlvbigpe3oucmVzb2x2ZSgpfSkpO3JldHVybiBlfSxsYj1mdW5jdGlvbihiKXt2YXIgZCxlPXRoaXM7aWYocyYmIXEpZS5kZWJ1Zy5sb2coXCJEYXRhIGNoYW5nZWQgLSBsb2FkaW5nIHRoZSBcIitjK1wiIGZyYWdtZW50IGZvciB0aW1lOiBcIithKSxkPWUuaW5kZXhIYW5kbGVyLmdldFNlZ21lbnRSZXF1ZXN0Rm9yVGltZShhLGIsTSk7ZWxzZXt2YXIgZj1RLmRlZmVyKCksZz1lLnZpZGVvTW9kZWwuZ2V0Q3VycmVudFRpbWUoKTtkPWYucHJvbWlzZSxlLnNvdXJjZUJ1ZmZlckV4dC5nZXRCdWZmZXJSYW5nZShOLGcpLnRoZW4oZnVuY3Rpb24oYSl7cT0hMSxudWxsIT09YSYmKGc9YS5lbmQpLGUuZGVidWcubG9nKFwiTG9hZGluZyB0aGUgXCIrYytcIiBmcmFnbWVudCBmb3IgdGltZTogXCIrZyksZS5pbmRleEhhbmRsZXIuZ2V0U2VnbWVudFJlcXVlc3RGb3JUaW1lKGcsYixNKS50aGVuKGZ1bmN0aW9uKGEpe2YucmVzb2x2ZShhKX0sZnVuY3Rpb24oKXtmLnJlamVjdCgpfSl9LGZ1bmN0aW9uKCl7Zi5yZWplY3QoKX0pfXJldHVybiBzPSExLGR9LG1iPWZ1bmN0aW9uKGEpe3ZhciBiPXRoaXM7bnVsbCE9PWE/Yi5mcmFnbWVudENvbnRyb2xsZXIuaXNGcmFnbWVudExvYWRlZE9yUGVuZGluZyhiLGEpP1wiY29tcGxldGVcIiE9PWEuYWN0aW9uP2IuaW5kZXhIYW5kbGVyLmdldE5leHRTZWdtZW50UmVxdWVzdCh0LE0pLnRoZW4obWIuYmluZChiKSk6KFkuY2FsbChiKSxTLmNhbGwoYixoKSk6KGIuZGVidWcubG9nKFwiTG9hZGluZyBhbiBcIitjK1wiIGZyYWdtZW50OiBcIithLnVybCksUS53aGVuKEM/Qy5wcm9taXNlOiEwKS50aGVuKGZ1bmN0aW9uKCl7Yi5mcmFnbWVudENvbnRyb2xsZXIucHJlcGFyZUZyYWdtZW50Rm9yTG9hZGluZyhiLGEsXyxhYixpYixqYikudGhlbihmdW5jdGlvbigpe1MuY2FsbChiLGgpfSl9KSk6Uy5jYWxsKGIsaCl9LG5iPWZ1bmN0aW9uKCl7biYmKGQ+SCYmZDxFLXRoaXMudmlkZW9Nb2RlbC5nZXRDdXJyZW50VGltZSgpP3V8fCh0aGlzLmRlYnVnLmxvZyhcIldhaXRpbmcgZm9yIG1vcmUgXCIrYytcIiBidWZmZXIgYmVmb3JlIHN0YXJ0aW5nIHBsYXliYWNrLlwiKSx1PSEwLHRoaXMudmlkZW9Nb2RlbC5zdGFsbFN0cmVhbShjLHUpKToodGhpcy5kZWJ1Zy5sb2coXCJHb3QgZW5vdWdoIFwiK2MrXCIgYnVmZmVyIHRvIHN0YXJ0LlwiKSxuPSExLHU9ITEsdGhpcy52aWRlb01vZGVsLnN0YWxsU3RyZWFtKGMsdSkpKX0sb2I9ZnVuY3Rpb24oKXt2YXIgYT0tMTtyZXR1cm4gYT10aGlzLnZpZGVvTW9kZWwuZ2V0Q3VycmVudFRpbWUoKX0scGI9ZnVuY3Rpb24oYSl7dmFyIGI9dGhpcyxjPWIudmlkZW9Nb2RlbC5nZXRQbGF5YmFja1JhdGUoKSxkPUgvTWF0aC5tYXgoYywxKSxlPVEuZGVmZXIoKTtyZXR1cm4gYi5idWZmZXJFeHQuZ2V0UmVxdWlyZWRCdWZmZXJMZW5ndGgobixiLnJlcXVlc3RTY2hlZHVsZXIuZ2V0RXhlY3V0ZUludGVydmFsKGIpLzFlMyx2LEUpLnRoZW4oZnVuY3Rpb24oYyl7Yi5pbmRleEhhbmRsZXIuZ2V0U2VnbWVudENvdW50Rm9yRHVyYXRpb24oYSxNLGMsZCkudGhlbihmdW5jdGlvbihhKXtlLnJlc29sdmUoYSl9KX0pLGUucHJvbWlzZX0scWI9ZnVuY3Rpb24oKXt2YXIgYT10aGlzLGI9YS5mcmFnbWVudENvbnRyb2xsZXIuZ2V0UGVuZGluZ1JlcXVlc3RzKGEpLGM9YS5mcmFnbWVudENvbnRyb2xsZXIuZ2V0TG9hZGluZ1JlcXVlc3RzKGEpLGQ9KGI/Yi5sZW5ndGg6MCkrKGM/Yy5sZW5ndGg6MCk7Ri1kPjA/KEYtLSxsYi5jYWxsKGEsdCkudGhlbihtYi5iaW5kKGEpKSk6KGs9PT1pJiZTLmNhbGwoYSxoKSwkLmNhbGwoYSkpfSxyYj1mdW5jdGlvbigpe3ZhciBhLGI9dGhpcyxkPSExLGY9bnVsbCxnPW5ldyBEYXRlLGw9Yi52aWRlb01vZGVsLmdldEN1cnJlbnRUaW1lKCksbT1vYi5jYWxsKGIpO2lmKGIuZGVidWcubG9nKFwiQnVmZmVyQ29udHJvbGxlci52YWxpZGF0ZSgpIFwiK2MrXCIgfCBzdGF0ZTogXCIrayksYi5kZWJ1Zy5sb2coYytcIiBQbGF5YmFjayByYXRlOiBcIitiLnZpZGVvTW9kZWwuZ2V0RWxlbWVudCgpLnBsYXliYWNrUmF0ZSksYi5kZWJ1Zy5sb2coYytcIiBXb3JraW5nIHRpbWU6IFwiK20pLGIuZGVidWcubG9nKGMrXCIgVmlkZW8gdGltZTogXCIrbCksYi5kZWJ1Zy5sb2coXCJDdXJyZW50IFwiK2MrXCIgYnVmZmVyIGxlbmd0aDogXCIrSCksbmIuY2FsbChiKSxrPT09aiYmZT5IKXV8fChiLmRlYnVnLmxvZyhcIlN0YWxsaW5nIFwiK2MrXCIgQnVmZmVyOiBcIitjKSxUKG5ldyBEYXRlLE1lZGlhUGxheWVyLnZvLm1ldHJpY3MuUGxheUxpc3QuVHJhY2UuUkVCVUZGRVJJTkdfUkVBU09OKSx1PSEwLG49ITAsYi52aWRlb01vZGVsLnN0YWxsU3RyZWFtKGMsdSkpO2Vsc2UgaWYoaz09PWgpe1MuY2FsbChiLGkpO3ZhciBvPWIubWFuaWZlc3RNb2RlbC5nZXRWYWx1ZSgpLm1pbkJ1ZmZlclRpbWU7Yi5idWZmZXJFeHQuZGVjaWRlQnVmZmVyTGVuZ3RoKG8sRSxuKS50aGVuKGZ1bmN0aW9uKGEpe2IuZGVidWcubG9nKFwiQnVmZmVyIHRpbWU6IFwiK2EpLGIuc2V0TWluQnVmZmVyVGltZShhKSxiLnJlcXVlc3RTY2hlZHVsZXIuYWRqdXN0RXhlY3V0ZUludGVydmFsKCl9KSxiLmFickNvbnRyb2xsZXIuZ2V0UGxheWJhY2tRdWFsaXR5KGMsTSkudGhlbihmdW5jdGlvbihlKXt2YXIgaD1lLnF1YWxpdHk7aWYoYi5kZWJ1Zy5sb2coYytcIiBQbGF5YmFjayBxdWFsaXR5OiBcIitoKSxiLmRlYnVnLmxvZyhcIlBvcHVsYXRlIFwiK2MrXCIgYnVmZmVycy5cIiksdm9pZCAwIT09aCYmKGE9aCksZD1oIT09dCxkPT09ITApe2lmKGIuZnJhZ21lbnRDb250cm9sbGVyLmFib3J0UmVxdWVzdHNGb3JNb2RlbChHKSxmPVooYSxiLmdldERhdGEoKSksbnVsbD09PWZ8fHZvaWQgMD09PWYpdGhyb3dcIlVuZXhwZWN0ZWQgZXJyb3IhXCI7Yi5tYW5pZmVzdEV4dC5nZXRUaW1lc3RhbXBPZmZzZXRGb3JQZXJpb2QoRCxiLm1hbmlmZXN0TW9kZWwuZ2V0VmFsdWUoKSxoLE0pLnRoZW4oZnVuY3Rpb24oYSl7Ti50aW1lc3RhbXBPZmZzZXQhPT1hJiYoTi50aW1lc3RhbXBPZmZzZXQ9YSl9KSxUKG5ldyBEYXRlLE1lZGlhUGxheWVyLnZvLm1ldHJpY3MuUGxheUxpc3QuVHJhY2UuUkVQUkVTRU5UQVRJT05fU1dJVENIX1NUT1BfUkVBU09OKSxiLm1ldHJpY3NNb2RlbC5hZGRSZXByZXNlbnRhdGlvblN3aXRjaChjLGcsbCxmLmlkKX1yZXR1cm4gYi5kZWJ1Zy5sb2coZD9jK1wiIFF1YWxpdHkgY2hhbmdlZCB0bzogXCIraDpcIlF1YWxpdHkgZGlkbid0IGNoYW5nZS5cIikscGIuY2FsbChiLGgpfSkudGhlbihmdW5jdGlvbihlKXtGPWUsa2IuY2FsbChiLGQsYSkudGhlbihmdW5jdGlvbihhKXtpZihudWxsIT09YSl7dmFyIGQsZSxmPWEubGVuZ3RoO2ZvcihlPTA7Zj5lO2UrPTEpZD1hW2VdLGIuZGVidWcubG9nKFwiTG9hZGluZyBcIitjK1wiIGluaXRpYWxpemF0aW9uOiBcIitkLnVybCksYi5kZWJ1Zy5sb2coZCksYi5mcmFnbWVudENvbnRyb2xsZXIucHJlcGFyZUZyYWdtZW50Rm9yTG9hZGluZyhiLGQsXyxhYixpYixqYikudGhlbihmdW5jdGlvbigpe1MuY2FsbChiLGgpfSl9fSkscWIuY2FsbChiKX0pfWVsc2Ugaz09PWkmJlMuY2FsbChiLGgpfTtyZXR1cm57dmlkZW9Nb2RlbDp2b2lkIDAsbWV0cmljc01vZGVsOnZvaWQgMCxtYW5pZmVzdEV4dDp2b2lkIDAsbWFuaWZlc3RNb2RlbDp2b2lkIDAsYnVmZmVyRXh0OnZvaWQgMCxzb3VyY2VCdWZmZXJFeHQ6dm9pZCAwLGFickNvbnRyb2xsZXI6dm9pZCAwLGZyYWdtZW50RXh0OnZvaWQgMCxpbmRleEhhbmRsZXI6dm9pZCAwLGRlYnVnOnZvaWQgMCxzeXN0ZW06dm9pZCAwLGVyckhhbmRsZXI6dm9pZCAwLGluaXRpYWxpemU6ZnVuY3Rpb24oYSxiLGMsZCxlLGYsZyxoKXt2YXIgaT10aGlzLGo9aS5tYW5pZmVzdE1vZGVsLmdldFZhbHVlKCksaz1pLm1hbmlmZXN0RXh0LmdldElzTGl2ZShqKTtpLnNldE1lZGlhU291cmNlKGgpLGkuc2V0VmlkZW9Nb2RlbChlKSxpLnNldFR5cGUoYSksaS5zZXRQZXJpb2RJbmRleChiKSxpLnNldERhdGEoYykudGhlbihmdW5jdGlvbigpe2w9ITAsVi5jYWxsKGkpfSksaS5zZXRCdWZmZXIoZCksaS5zZXRTY2hlZHVsZXIoZiksaS5zZXRGcmFnbWVudENvbnRyb2xsZXIoZyksaS5pbmRleEhhbmRsZXIuc2V0SXNMaXZlKGspLGkubWFuaWZlc3RFeHQuZ2V0RHVyYXRpb25Gb3JQZXJpb2QoYixpLm1hbmlmZXN0TW9kZWwuZ2V0VmFsdWUoKSkudGhlbihmdW5jdGlvbihhKXtFPWEsaS5pbmRleEhhbmRsZXIuc2V0RHVyYXRpb24oYSksaS5idWZmZXJFeHQuZGVjaWRlQnVmZmVyTGVuZ3RoKGoubWluQnVmZmVyVGltZSxFLG4pLnRoZW4oZnVuY3Rpb24oYSl7aS5zZXRNaW5CdWZmZXJUaW1lKGEpfSl9KX0sZ2V0VHlwZTpmdW5jdGlvbigpe3JldHVybiBjfSxzZXRUeXBlOmZ1bmN0aW9uKGEpe2M9YSx2b2lkIDAhPT10aGlzLmluZGV4SGFuZGxlciYmdGhpcy5pbmRleEhhbmRsZXIuc2V0VHlwZShhKX0sZ2V0UGVyaW9kSW5kZXg6ZnVuY3Rpb24oKXtyZXR1cm4gRH0sc2V0UGVyaW9kSW5kZXg6ZnVuY3Rpb24oYSl7RD1hfSxnZXRWaWRlb01vZGVsOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMudmlkZW9Nb2RlbH0sc2V0VmlkZW9Nb2RlbDpmdW5jdGlvbihhKXt0aGlzLnZpZGVvTW9kZWw9YX0sZ2V0U2NoZWR1bGVyOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMucmVxdWVzdFNjaGVkdWxlcn0sc2V0U2NoZWR1bGVyOmZ1bmN0aW9uKGEpe3RoaXMucmVxdWVzdFNjaGVkdWxlcj1hfSxnZXRGcmFnbWVudENvbnRyb2xsZXI6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5mcmFnbWVudENvbnRyb2xsZXJ9LHNldEZyYWdtZW50Q29udHJvbGxlcjpmdW5jdGlvbihhKXt0aGlzLmZyYWdtZW50Q29udHJvbGxlcj1hfSxnZXRBdXRvU3dpdGNoQml0cmF0ZTpmdW5jdGlvbigpe3ZhciBhPXRoaXM7cmV0dXJuIGEuYWJyQ29udHJvbGxlci5nZXRBdXRvU3dpdGNoQml0cmF0ZSgpfSxzZXRBdXRvU3dpdGNoQml0cmF0ZTpmdW5jdGlvbihhKXt2YXIgYj10aGlzO2IuYWJyQ29udHJvbGxlci5zZXRBdXRvU3dpdGNoQml0cmF0ZShhKX0sZ2V0RGF0YTpmdW5jdGlvbigpe3JldHVybiBNfSxzZXREYXRhOmZ1bmN0aW9uKGIpe3ZhciBkPXRoaXMsZT1RLmRlZmVyKCksZj1NO3JldHVybiBmfHwoZj1iKSxkLmFickNvbnRyb2xsZXIuZ2V0UGxheWJhY2tRdWFsaXR5KGMsZikudGhlbihmdW5jdGlvbihnKXtkLmluZGV4SGFuZGxlci5nZXRDdXJyZW50VGltZShnLnF1YWxpdHksZikudGhlbihmdW5jdGlvbihmKXtzPSEwLGE9ZixNPWIsZC5zZWVrKGYpLGQuYnVmZmVyRXh0LnVwZGF0ZURhdGEoTSxjKSxlLnJlc29sdmUoKX0pfSksZS5wcm9taXNlfSxnZXRCdWZmZXI6ZnVuY3Rpb24oKXtyZXR1cm4gTn0sc2V0QnVmZmVyOmZ1bmN0aW9uKGEpe049YX0sZ2V0TWluQnVmZmVyVGltZTpmdW5jdGlvbigpe3JldHVybiBkfSxzZXRNaW5CdWZmZXJUaW1lOmZ1bmN0aW9uKGEpe2Q9YX0sc2V0TWVkaWFTb3VyY2U6ZnVuY3Rpb24oYSl7Yj1hfSxpc1JlYWR5OmZ1bmN0aW9uKCl7cmV0dXJuIGs9PT1ofSxpc0J1ZmZlcmluZ0NvbXBsZXRlZDpmdW5jdGlvbigpe3JldHVybiB4fSxjbGVhck1ldHJpY3M6ZnVuY3Rpb24oKXt2YXIgYT10aGlzO251bGwhPT1jJiZcIlwiIT09YyYmYS5tZXRyaWNzTW9kZWwuY2xlYXJDdXJyZW50TWV0cmljc0ZvclR5cGUoYyl9LHVwZGF0ZUJ1ZmZlclN0YXRlOmZ1bmN0aW9uKCl7dmFyIGE9dGhpcztJJiZKJiYhTD8oTD0hMCxjYi5jYWxsKGEsSix0KS50aGVuKGZ1bmN0aW9uKCl7TD0hMX0pKTpkYi5jYWxsKGEpfSxyZXNldDpmdW5jdGlvbihhKXt2YXIgYz10aGlzO1kuY2FsbChjKSxjLmNsZWFyTWV0cmljcygpLGMuZnJhZ21lbnRDb250cm9sbGVyLmFib3J0UmVxdWVzdHNGb3JNb2RlbChHKSxjLmZyYWdtZW50Q29udHJvbGxlci5kZXRhY2hCdWZmZXJDb250cm9sbGVyKEcpLEc9bnVsbCx5PVtdLHo9bnVsbCxwPVtdLEE9US5kZWZlcigpLGF8fChjLnNvdXJjZUJ1ZmZlckV4dC5hYm9ydChiLE4pLGMuc291cmNlQnVmZmVyRXh0LnJlbW92ZVNvdXJjZUJ1ZmZlcihiLE4pKSxNPW51bGwsTj1udWxsfSxzdGFydDpXLHNlZWs6WCxzdG9wOll9fSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuQnVmZmVyQ29udHJvbGxlci5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOk1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5CdWZmZXJDb250cm9sbGVyfSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuQnVmZmVyRXh0ZW5zaW9ucz1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3ZhciBhLGIsYz0wLGQ9MCxlPW51bGwsZj1udWxsLGc9ZnVuY3Rpb24oYSl7dmFyIGI9dGhpcy5tZXRyaWNzRXh0LmdldEN1cnJlbnRIdHRwUmVxdWVzdChhKTtyZXR1cm4gbnVsbCE9PWI/KGIudHJlc3BvbnNlLmdldFRpbWUoKS1iLnRyZXF1ZXN0LmdldFRpbWUoKSkvMWUzOjB9LGg9ZnVuY3Rpb24oKXt2YXIgYSxiPXRoaXMsZz1RLmRlZmVyKCk7cmV0dXJuIFEud2hlbihlP2IuYWJyQ29udHJvbGxlci5nZXRQbGF5YmFja1F1YWxpdHkoXCJhdWRpb1wiLGUpOmMpLnRoZW4oZnVuY3Rpb24oZSl7US53aGVuKGY/Yi5hYnJDb250cm9sbGVyLmdldFBsYXliYWNrUXVhbGl0eShcInZpZGVvXCIsZik6ZCkudGhlbihmdW5jdGlvbihiKXthPWUucXVhbGl0eT09PWMmJmIucXVhbGl0eT09PWQsYT1hfHxlLmNvbmZpZGVuY2U9PT1NZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0LnByb3RvdHlwZS5TVFJPTkcmJmIuY29uZmlkZW5jZT09PU1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlLlNUUk9ORyxnLnJlc29sdmUoYSl9KX0pLGcucHJvbWlzZX07cmV0dXJue3N5c3RlbTp2b2lkIDAsdmlkZW9Nb2RlbDp2b2lkIDAsbWFuaWZlc3RFeHQ6dm9pZCAwLG1ldHJpY3NFeHQ6dm9pZCAwLG1ldHJpY3NNb2RlbDp2b2lkIDAsYWJyQ29udHJvbGxlcjp2b2lkIDAsYnVmZmVyTWF4OnZvaWQgMCx1cGRhdGVEYXRhOmZ1bmN0aW9uKGEsYil7dmFyIGc9YS5SZXByZXNlbnRhdGlvbl9hc0FycmF5Lmxlbmd0aC0xO1wiYXVkaW9cIj09PWI/KGM9ZyxlPWEpOlwidmlkZW9cIj09PWImJihkPWcsZj1hKX0sZ2V0VG9wUXVhbGl0eUluZGV4OmZ1bmN0aW9uKGEpe3ZhciBiPW51bGw7cmV0dXJuXCJhdWRpb1wiPT09YT9iPWM6XCJ2aWRlb1wiPT09YSYmKGI9ZCksYn0sZGVjaWRlQnVmZmVyTGVuZ3RoOmZ1bmN0aW9uKGIsYyl7cmV0dXJuIGE9TWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLkJ1ZmZlckV4dGVuc2lvbnMuREVGQVVMVF9NSU5fQlVGRkVSX1RJTUU8YyYmYz5iP01hdGgubWF4KE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5CdWZmZXJFeHRlbnNpb25zLkRFRkFVTFRfTUlOX0JVRkZFUl9USU1FLGIpOmI+PWM/TWF0aC5taW4oYyxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuQnVmZmVyRXh0ZW5zaW9ucy5ERUZBVUxUX01JTl9CVUZGRVJfVElNRSk6TWF0aC5taW4oYyxiKSxRLndoZW4oYSl9LGdldExlYXN0QnVmZmVyTGV2ZWw6ZnVuY3Rpb24oKXt2YXIgYT10aGlzLm1ldHJpY3NNb2RlbC5nZXRSZWFkT25seU1ldHJpY3NGb3IoXCJ2aWRlb1wiKSxiPXRoaXMubWV0cmljc0V4dC5nZXRDdXJyZW50QnVmZmVyTGV2ZWwoYSksYz10aGlzLm1ldHJpY3NNb2RlbC5nZXRSZWFkT25seU1ldHJpY3NGb3IoXCJhdWRpb1wiKSxkPXRoaXMubWV0cmljc0V4dC5nZXRDdXJyZW50QnVmZmVyTGV2ZWwoYyksZT1udWxsO3JldHVybiBlPW51bGw9PT1ifHxudWxsPT09ZD9udWxsIT09ZD9kLmxldmVsOm51bGwhPT1iP2IubGV2ZWw6bnVsbDpNYXRoLm1pbihkLmxldmVsLGIubGV2ZWwpfSxnZXRSZXF1aXJlZEJ1ZmZlckxlbmd0aDpmdW5jdGlvbihjLGQsZSxmKXt2YXIgaSxqPXRoaXMsaz1qLm1ldHJpY3NNb2RlbC5nZXRSZWFkT25seU1ldHJpY3NGb3IoXCJ2aWRlb1wiKSxsPWoubWV0cmljc01vZGVsLmdldFJlYWRPbmx5TWV0cmljc0ZvcihcImF1ZGlvXCIpLG09Zj49TWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLkJ1ZmZlckV4dGVuc2lvbnMuTE9OR19GT1JNX0NPTlRFTlRfRFVSQVRJT05fVEhSRVNIT0xELG49US5kZWZlcigpLG89bnVsbDtyZXR1cm4gai5idWZmZXJNYXg9PT1NZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuQnVmZmVyRXh0ZW5zaW9ucy5CVUZGRVJfU0laRV9NSU4/KGk9YSxuLnJlc29sdmUoaSkpOmouYnVmZmVyTWF4PT09TWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLkJ1ZmZlckV4dGVuc2lvbnMuQlVGRkVSX1NJWkVfSU5GSU5JVFk/KGk9ZixuLnJlc29sdmUoaSkpOmouYnVmZmVyTWF4PT09TWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLkJ1ZmZlckV4dGVuc2lvbnMuQlVGRkVSX1NJWkVfUkVRVUlSRUQ/KGI9YSxlfHxjfHwobz1oLmNhbGwoaikpLFEud2hlbihvKS50aGVuKGZ1bmN0aW9uKGEpe2EmJihiPW0/TWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLkJ1ZmZlckV4dGVuc2lvbnMuQlVGRkVSX1RJTUVfQVRfVE9QX1FVQUxJVFlfTE9OR19GT1JNOk1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5CdWZmZXJFeHRlbnNpb25zLkJVRkZFUl9USU1FX0FUX1RPUF9RVUFMSVRZKSxpPWIrZCtNYXRoLm1heChnLmNhbGwoaixrKSxnLmNhbGwoaixsKSksbi5yZXNvbHZlKGkpfSkpOm4ucmVqZWN0KFwiaW52YWxpZCBidWZmZXJNYXggdmFsdWU6IFwiK2ouYnVmZmVyTWF4KSxuLnByb21pc2V9LGdldEJ1ZmZlclRhcmdldDpmdW5jdGlvbigpe3JldHVybiB2b2lkIDA9PT1iP2E6Yn19fSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuQnVmZmVyRXh0ZW5zaW9ucy5CVUZGRVJfU0laRV9SRVFVSVJFRD1cInJlcXVpcmVkXCIsTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLkJ1ZmZlckV4dGVuc2lvbnMuQlVGRkVSX1NJWkVfTUlOPVwibWluXCIsTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLkJ1ZmZlckV4dGVuc2lvbnMuQlVGRkVSX1NJWkVfSU5GSU5JVFk9XCJpbmZpbml0eVwiLE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5CdWZmZXJFeHRlbnNpb25zLkJVRkZFUl9USU1FX0FUX1NUQVJUVVA9MSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuQnVmZmVyRXh0ZW5zaW9ucy5ERUZBVUxUX01JTl9CVUZGRVJfVElNRT04LE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5CdWZmZXJFeHRlbnNpb25zLkJVRkZFUl9USU1FX0FUX1RPUF9RVUFMSVRZPTMwLE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5CdWZmZXJFeHRlbnNpb25zLkJVRkZFUl9USU1FX0FUX1RPUF9RVUFMSVRZX0xPTkdfRk9STT0zMDAsTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLkJ1ZmZlckV4dGVuc2lvbnMuTE9OR19GT1JNX0NPTlRFTlRfRFVSQVRJT05fVEhSRVNIT0xEPTYwMCxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuQnVmZmVyRXh0ZW5zaW9ucy5wcm90b3R5cGUuY29uc3RydWN0b3I9TWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLkJ1ZmZlckV4dGVuc2lvbnMsTWVkaWFQbGF5ZXIudXRpbHMuQ2FwYWJpbGl0aWVzPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCJ9LE1lZGlhUGxheWVyLnV0aWxzLkNhcGFiaWxpdGllcy5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOk1lZGlhUGxheWVyLnV0aWxzLkNhcGFiaWxpdGllcyxzdXBwb3J0c01lZGlhU291cmNlOmZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGE9XCJXZWJLaXRNZWRpYVNvdXJjZVwiaW4gd2luZG93LGI9XCJNZWRpYVNvdXJjZVwiaW4gd2luZG93O3JldHVybiBhfHxifSxzdXBwb3J0c01lZGlhS2V5czpmdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3ZhciBhPVwiV2ViS2l0TWVkaWFLZXlzXCJpbiB3aW5kb3csYj1cIk1TTWVkaWFLZXlzXCJpbiB3aW5kb3csYz1cIk1lZGlhS2V5c1wiaW4gd2luZG93O3JldHVybiBhfHxifHxjfSxzdXBwb3J0c0NvZGVjOmZ1bmN0aW9uKGEsYil7XCJ1c2Ugc3RyaWN0XCI7aWYoIShhIGluc3RhbmNlb2YgSFRNTFZpZGVvRWxlbWVudCkpdGhyb3dcImVsZW1lbnQgbXVzdCBiZSBvZiB0eXBlIEhUTUxWaWRlb0VsZW1lbnQuXCI7dmFyIGM9YS5jYW5QbGF5VHlwZShiKTtyZXR1cm5cInByb2JhYmx5XCI9PT1jfX0sTWVkaWFQbGF5ZXIudXRpbHMuRGVidWc9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt2YXIgYT0hMDtyZXR1cm57ZXZlbnRCdXM6dm9pZCAwLHNldExvZ1RvQnJvd3NlckNvbnNvbGU6ZnVuY3Rpb24oYil7YT1ifSxnZXRMb2dUb0Jyb3dzZXJDb25zb2xlOmZ1bmN0aW9uKCl7cmV0dXJuIGF9LGxvZzpmdW5jdGlvbihiKXthJiZjb25zb2xlLmxvZyhiKSx0aGlzLmV2ZW50QnVzLmRpc3BhdGNoRXZlbnQoe3R5cGU6XCJsb2dcIixtZXNzYWdlOmJ9KX19fSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuRXJyb3JIYW5kbGVyPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7cmV0dXJue2V2ZW50QnVzOnZvaWQgMCxjYXBhYmlsaXR5RXJyb3I6ZnVuY3Rpb24oYSl7dGhpcy5ldmVudEJ1cy5kaXNwYXRjaEV2ZW50KHt0eXBlOlwiZXJyb3JcIixlcnJvcjpcImNhcGFiaWxpdHlcIixldmVudDphfSl9LGRvd25sb2FkRXJyb3I6ZnVuY3Rpb24oYSxiLGMpe3RoaXMuZXZlbnRCdXMuZGlzcGF0Y2hFdmVudCh7dHlwZTpcImVycm9yXCIsZXJyb3I6XCJkb3dubG9hZFwiLGV2ZW50OntpZDphLHVybDpiLHJlcXVlc3Q6Y319KX0sbWFuaWZlc3RFcnJvcjpmdW5jdGlvbihhLGIsYyl7dGhpcy5ldmVudEJ1cy5kaXNwYXRjaEV2ZW50KHt0eXBlOlwiZXJyb3JcIixlcnJvcjpcIm1hbmlmZXN0RXJyb3JcIixldmVudDp7bWVzc2FnZTphLGlkOmIsbWFuaWZlc3Q6Y319KX0sbWVkaWFTb3VyY2VFcnJvcjpmdW5jdGlvbihhKXt0aGlzLmV2ZW50QnVzLmRpc3BhdGNoRXZlbnQoe3R5cGU6XCJlcnJvclwiLGVycm9yOlwibWVkaWFzb3VyY2VcIixldmVudDphfSl9LG1lZGlhS2V5U2Vzc2lvbkVycm9yOmZ1bmN0aW9uKGEpe3RoaXMuZXZlbnRCdXMuZGlzcGF0Y2hFdmVudCh7dHlwZTpcImVycm9yXCIsZXJyb3I6XCJrZXlfc2Vzc2lvblwiLGV2ZW50OmF9KX0sbWVkaWFLZXlNZXNzYWdlRXJyb3I6ZnVuY3Rpb24oYSl7dGhpcy5ldmVudEJ1cy5kaXNwYXRjaEV2ZW50KHt0eXBlOlwiZXJyb3JcIixlcnJvcjpcImtleV9tZXNzYWdlXCIsZXZlbnQ6YX0pfSxtZWRpYUtleVN5c3RlbVNlbGVjdGlvbkVycm9yOmZ1bmN0aW9uKGEpe3RoaXMuZXZlbnRCdXMuZGlzcGF0Y2hFdmVudCh7dHlwZTpcImVycm9yXCIsZXJyb3I6XCJrZXlfc3lzdGVtX3NlbGVjdGlvblwiLGV2ZW50OmF9KX19fSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuRXJyb3JIYW5kbGVyLnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLkVycm9ySGFuZGxlcn0sTWVkaWFQbGF5ZXIudXRpbHMuRXZlbnRCdXM9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt2YXIgYSxiPWZ1bmN0aW9uKGIsYyl7dmFyIGQ9KGM/XCIxXCI6XCIwXCIpK2I7cmV0dXJuIGQgaW4gYXx8KGFbZF09W10pLGFbZF19LGM9ZnVuY3Rpb24oKXthPXt9fTtyZXR1cm4gYygpLHthZGRFdmVudExpc3RlbmVyOmZ1bmN0aW9uKGEsYyxkKXt2YXIgZT1iKGEsZCksZj1lLmluZGV4T2YoYyk7LTE9PT1mJiZlLnB1c2goYyl9LHJlbW92ZUV2ZW50TGlzdGVuZXI6ZnVuY3Rpb24oYSxjLGQpe3ZhciBlPWIoYSxkKSxmPWUuaW5kZXhPZihjKTstMSE9PWYmJmUuc3BsaWNlKGYsMSl9LGRpc3BhdGNoRXZlbnQ6ZnVuY3Rpb24oYSl7Zm9yKHZhciBjPWIoYS50eXBlLCExKS5zbGljZSgpLGQ9MDtkPGMubGVuZ3RoO2QrKyljW2RdLmNhbGwodGhpcyxhKTtyZXR1cm4hYS5kZWZhdWx0UHJldmVudGVkfX19LE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5GcmFnbWVudENvbnRyb2xsZXI9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt2YXIgYT1bXSxiPWZ1bmN0aW9uKGIpe2Zvcih2YXIgYz1hLmxlbmd0aCxkPTA7Yz5kO2QrKylpZihhW2RdLmdldENvbnRleHQoKT09YilyZXR1cm4gYVtkXTtyZXR1cm4gbnVsbH0sYz1mdW5jdGlvbigpe2Zvcih2YXIgYj0hMCxjPWEubGVuZ3RoLGQ9MDtjPmQ7ZCsrKWlmKCFhW2RdLmlzUmVhZHkoKSl7Yj0hMTticmVha31yZXR1cm4gYn0sZD1mdW5jdGlvbigpe2Zvcih2YXIgYj0wO2I8YS5sZW5ndGg7YisrKWFbYl0uZXhlY3V0ZUN1cnJlbnRSZXF1ZXN0KCl9O3JldHVybntzeXN0ZW06dm9pZCAwLGRlYnVnOnZvaWQgMCxwcm9jZXNzOmZ1bmN0aW9uKGEpe3ZhciBiPW51bGw7cmV0dXJuIG51bGwhPT1hJiZ2b2lkIDAhPT1hJiZhLmJ5dGVMZW5ndGg+MCYmKGI9bmV3IFVpbnQ4QXJyYXkoYSkpLFEud2hlbihiKX0sYXR0YWNoQnVmZmVyQ29udHJvbGxlcjpmdW5jdGlvbihjKXtpZighYylyZXR1cm4gbnVsbDt2YXIgZD1iKGMpO3JldHVybiBkfHwoZD10aGlzLnN5c3RlbS5nZXRPYmplY3QoXCJmcmFnbWVudE1vZGVsXCIpLGQuc2V0Q29udGV4dChjKSxhLnB1c2goZCkpLGR9LGRldGFjaEJ1ZmZlckNvbnRyb2xsZXI6ZnVuY3Rpb24oYil7dmFyIGM9YS5pbmRleE9mKGIpO2M+LTEmJmEuc3BsaWNlKGMsMSl9LG9uQnVmZmVyQ29udHJvbGxlclN0YXRlQ2hhbmdlOmZ1bmN0aW9uKCl7YygpJiZkLmNhbGwodGhpcyl9LGlzRnJhZ21lbnRMb2FkZWRPclBlbmRpbmc6ZnVuY3Rpb24oYSxjKXt2YXIgZCxlPWIoYSk7cmV0dXJuIGU/ZD1lLmlzRnJhZ21lbnRMb2FkZWRPclBlbmRpbmcoYyk6ITF9LGdldFBlbmRpbmdSZXF1ZXN0czpmdW5jdGlvbihhKXt2YXIgYz1iKGEpO3JldHVybiBjP2MuZ2V0UGVuZGluZ1JlcXVlc3RzKCk6bnVsbH0sZ2V0TG9hZGluZ1JlcXVlc3RzOmZ1bmN0aW9uKGEpe3ZhciBjPWIoYSk7cmV0dXJuIGM/Yy5nZXRMb2FkaW5nUmVxdWVzdHMoKTpudWxsfSxpc0luaXRpYWxpemF0aW9uUmVxdWVzdDpmdW5jdGlvbihhKXtyZXR1cm4gYSYmYS50eXBlJiZcImluaXRpYWxpemF0aW9uIHNlZ21lbnRcIj09PWEudHlwZS50b0xvd2VyQ2FzZSgpfSxnZXRMb2FkaW5nVGltZTpmdW5jdGlvbihhKXt2YXIgYz1iKGEpO3JldHVybiBjP2MuZ2V0TG9hZGluZ1RpbWUoKTpudWxsfSxnZXRFeGVjdXRlZFJlcXVlc3RGb3JUaW1lOmZ1bmN0aW9uKGEsYil7cmV0dXJuIGE/YS5nZXRFeGVjdXRlZFJlcXVlc3RGb3JUaW1lKGIpOm51bGx9LHJlbW92ZUV4ZWN1dGVkUmVxdWVzdDpmdW5jdGlvbihhLGIpe2EmJmEucmVtb3ZlRXhlY3V0ZWRSZXF1ZXN0KGIpfSxyZW1vdmVFeGVjdXRlZFJlcXVlc3RzQmVmb3JlVGltZTpmdW5jdGlvbihhLGIpe2EmJmEucmVtb3ZlRXhlY3V0ZWRSZXF1ZXN0c0JlZm9yZVRpbWUoYil9LGNhbmNlbFBlbmRpbmdSZXF1ZXN0c0Zvck1vZGVsOmZ1bmN0aW9uKGEpe2EmJmEuY2FuY2VsUGVuZGluZ1JlcXVlc3RzKCl9LGFib3J0UmVxdWVzdHNGb3JNb2RlbDpmdW5jdGlvbihhKXthJiZhLmFib3J0UmVxdWVzdHMoKX0scHJlcGFyZUZyYWdtZW50Rm9yTG9hZGluZzpmdW5jdGlvbihhLGMsZCxlLGYsZyl7dmFyIGg9YihhKTtyZXR1cm4gaCYmYyYmIXRoaXMuaXNGcmFnbWVudExvYWRlZE9yUGVuZGluZyhhLGMpPyhoLmFkZFJlcXVlc3QoYyksaC5zZXRDYWxsYmFja3MoZCxlLGYsZyksUS53aGVuKCEwKSk6US53aGVuKG51bGwpfX19LE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5GcmFnbWVudENvbnRyb2xsZXIucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuRnJhZ21lbnRDb250cm9sbGVyfSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuRnJhZ21lbnRMb2FkZXI9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt2YXIgYT0zLGI9NTAwLGM9W10sZD1mdW5jdGlvbihhLGUpe3ZhciBmPW5ldyBYTUxIdHRwUmVxdWVzdCxnPW51bGwsaD0hMCxpPSEwLGo9dGhpcztjLnB1c2goZiksYS5yZXF1ZXN0U3RhcnREYXRlPW5ldyBEYXRlLGEuZmlyc3RCeXRlRGF0ZT1hLnJlcXVlc3RTdGFydERhdGUsZi5vcGVuKFwiR0VUXCIsYS51cmwsITApLGYucmVzcG9uc2VUeXBlPVwiYXJyYXlidWZmZXJcIixhLnJhbmdlJiZmLnNldFJlcXVlc3RIZWFkZXIoXCJSYW5nZVwiLFwiYnl0ZXM9XCIrYS5yYW5nZSksZi5vbnByb2dyZXNzPWZ1bmN0aW9uKGIpe2gmJihoPSExLCghYi5sZW5ndGhDb21wdXRhYmxlfHxiLmxlbmd0aENvbXB1dGFibGUmJmIudG90YWwhPWIubG9hZGVkKSYmKGEuZmlyc3RCeXRlRGF0ZT1uZXcgRGF0ZSkpfSxmLm9ubG9hZD1mdW5jdGlvbigpe2lmKCEoZi5zdGF0dXM8MjAwfHxmLnN0YXR1cz4yOTkpKXtpPSExLGEucmVxdWVzdEVuZERhdGU9bmV3IERhdGU7dmFyIGI9YS5yZXF1ZXN0RW5kRGF0ZSxjPWYucmVzcG9uc2UsZD1hLmZpcnN0Qnl0ZURhdGUuZ2V0VGltZSgpLWEucmVxdWVzdFN0YXJ0RGF0ZS5nZXRUaW1lKCksZT1hLnJlcXVlc3RFbmREYXRlLmdldFRpbWUoKS1hLmZpcnN0Qnl0ZURhdGUuZ2V0VGltZSgpLGg9YS5yZXF1ZXN0RW5kRGF0ZS5nZXRUaW1lKCktYS5yZXF1ZXN0U3RhcnREYXRlLmdldFRpbWUoKTtqLmRlYnVnLmxvZyhcInNlZ21lbnQgbG9hZGVkOiAoXCIrZi5zdGF0dXMrXCIsIFwiK2QrXCJtcywgXCIrZStcIm1zLCBcIitoK1wibXMpIFwiK2EudXJsKSxnPWoubWV0cmljc01vZGVsLmFkZEh0dHBSZXF1ZXN0KGEuc3RyZWFtVHlwZSxudWxsLGEudHlwZSxhLnVybCxudWxsLGEucmFuZ2UsYS5yZXF1ZXN0U3RhcnREYXRlLGEuZmlyc3RCeXRlRGF0ZSxhLnJlcXVlc3RFbmREYXRlLGYuc3RhdHVzLG51bGwsYS5kdXJhdGlvbiksai5tZXRyaWNzTW9kZWwuYXBwZW5kSHR0cFRyYWNlKGcsYiwobmV3IERhdGUpLmdldFRpbWUoKS1iLmdldFRpbWUoKSxbYy5ieXRlTGVuZ3RoXSksYS5kZWZlcnJlZC5yZXNvbHZlKHtkYXRhOmMscmVxdWVzdDphfSl9fSxmLm9ubG9hZGVuZD1mLm9uZXJyb3I9ZnVuY3Rpb24oKXtpZigtMSE9PWMuaW5kZXhPZihmKSYmKGMuc3BsaWNlKGMuaW5kZXhPZihmKSwxKSxpKSl7aT0hMSxhLnJlcXVlc3RFbmREYXRlPW5ldyBEYXRlO3ZhciBoPWEuZmlyc3RCeXRlRGF0ZS5nZXRUaW1lKCktYS5yZXF1ZXN0U3RhcnREYXRlLmdldFRpbWUoKSxrPWEucmVxdWVzdEVuZERhdGUuZ2V0VGltZSgpLWEuZmlyc3RCeXRlRGF0ZS5nZXRUaW1lKCksbD1hLnJlcXVlc3RFbmREYXRlLmdldFRpbWUoKS1hLnJlcXVlc3RTdGFydERhdGUuZ2V0VGltZSgpO2ouZGVidWcubG9nKFwic2VnbWVudCBsb2FkZWQ6IChcIitmLnN0YXR1cytcIiwgXCIraCtcIm1zLCBcIitrK1wibXMsIFwiK2wrXCJtcykgXCIrYS51cmwpLGc9ai5tZXRyaWNzTW9kZWwuYWRkSHR0cFJlcXVlc3QoYS5zdHJlYW1UeXBlLG51bGwsYS50eXBlLGEudXJsLG51bGwsYS5yYW5nZSxhLnJlcXVlc3RTdGFydERhdGUsYS5maXJzdEJ5dGVEYXRlLGEucmVxdWVzdEVuZERhdGUsZi5zdGF0dXMsbnVsbCxhLmR1cmF0aW9uKSxlPjA/KGouZGVidWcubG9nKFwiRmFpbGVkIGxvYWRpbmcgc2VnbWVudDogXCIrYS51cmwrXCIsIHJldHJ5IGluIFwiK2IrXCJtc1wiK1wiIGF0dGVtcHRzOiBcIitlKSxlLS0sc2V0VGltZW91dChmdW5jdGlvbigpe2QuY2FsbChqLGEsZSl9LGIpKTooai5kZWJ1Zy5sb2coXCJGYWlsZWQgbG9hZGluZyBzZWdtZW50OiBcIithLnVybCtcIiBubyByZXRyeSBhdHRlbXB0cyBsZWZ0XCIpLGouZXJySGFuZGxlci5kb3dubG9hZEVycm9yKFwiY29udGVudFwiLGEudXJsLGYpLGEuZGVmZXJyZWQucmVqZWN0KGYpKX19LGYuc2VuZCgpfTtyZXR1cm57bWV0cmljc01vZGVsOnZvaWQgMCxlcnJIYW5kbGVyOnZvaWQgMCxkZWJ1Zzp2b2lkIDAsbG9hZDpmdW5jdGlvbihiKXtyZXR1cm4gYj8oYi5kZWZlcnJlZD1RLmRlZmVyKCksZC5jYWxsKHRoaXMsYixhKSxiLmRlZmVycmVkLnByb21pc2UpOlEud2hlbihudWxsKX0sYWJvcnQ6ZnVuY3Rpb24oKXt2YXIgYSxiLGQ9Yy5sZW5ndGg7Zm9yKGE9MDtkPmE7YSs9MSliPWNbYV0sY1thXT1udWxsLGIuYWJvcnQoKSxiPW51bGw7Yz1bXX19fSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuRnJhZ21lbnRMb2FkZXIucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuRnJhZ21lbnRMb2FkZXJ9LE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5GcmFnbWVudE1vZGVsPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGEsYixjLGQsZSxmPVtdLGc9W10saD1bXSxpPTUsaj1mdW5jdGlvbihlKXt2YXIgZyxpPXRoaXM7Yi5jYWxsKGEsZSksZz1mdW5jdGlvbihiLGQpe2guc3BsaWNlKGguaW5kZXhPZihiKSwxKSxmLnB1c2goYiksYy5jYWxsKGEsYixkKSxiLmRlZmVycmVkPW51bGx9LGkuZnJhZ21lbnRMb2FkZXIubG9hZChlKS50aGVuKGcuYmluZChhLGUpLGQuYmluZChhLGUpKX0saz1mdW5jdGlvbihhLGIpe3ZhciBjPWZ1bmN0aW9uKGEsYyl7cmV0dXJuIGFbYl08Y1tiXT8tMTphW2JdPmNbYl0/MTowfTthLnNvcnQoYyl9LGw9ZnVuY3Rpb24oYSxiKXt2YXIgYyxkLGU9YS5sZW5ndGgtMTtmb3IoZD1lO2Q+PTA7ZC09MSlpZihjPWFbZF0sYy51cmw9PT1iLnVybCYmYy5zdGFydFRpbWU9PT1iLnN0YXJ0VGltZSlyZXR1cm4hMDtyZXR1cm4hMX0sbT1mdW5jdGlvbihhKXt2YXIgYj1mLmluZGV4T2YoYSk7LTEhPT1iJiZmLnNwbGljZShiLDEpfTtyZXR1cm57c3lzdGVtOnZvaWQgMCxkZWJ1Zzp2b2lkIDAsZnJhZ21lbnRMb2FkZXI6dm9pZCAwLHNldENvbnRleHQ6ZnVuY3Rpb24oYil7YT1ifSxnZXRDb250ZXh0OmZ1bmN0aW9uKCl7cmV0dXJuIGF9LGFkZFJlcXVlc3Q6ZnVuY3Rpb24oYSl7YSYmKGcucHVzaChhKSxrLmNhbGwodGhpcyxnLFwiaW5kZXhcIikpfSxzZXRDYWxsYmFja3M6ZnVuY3Rpb24oYSxmLGcsaCl7Yj1hLGU9aCxkPWcsYz1mfSxpc0ZyYWdtZW50TG9hZGVkT3JQZW5kaW5nOmZ1bmN0aW9uKGEpe2Zvcih2YXIgYixjPXRoaXMsZD0hMSxlPWYubGVuZ3RoLTEsaT1lO2k+PTA7aS09MSlpZihiPWZbaV0sYS5zdGFydFRpbWU9PT1iLnN0YXJ0VGltZXx8XCJjb21wbGV0ZVwiPT09Yi5hY3Rpb24mJmEuYWN0aW9uPT09Yi5hY3Rpb24pe2lmKGMuZGVidWcubG9nKGEuc3RyZWFtVHlwZStcIiBGcmFnbWVudCBhbHJlYWR5IGxvYWRlZCBmb3IgdGltZTogXCIrYS5zdGFydFRpbWUpLGEudXJsPT09Yi51cmwpe2MuZGVidWcubG9nKGEuc3RyZWFtVHlwZStcIiBGcmFnbWVudCB1cmwgYWxyZWFkeSBsb2FkZWQ6IFwiK2EudXJsKSxkPSEwO2JyZWFrfW0oYSl9cmV0dXJuIGR8fChkPWwuY2FsbChjLGcsYSl8fGwuY2FsbChjLGgsYSkpLGR9LGlzUmVhZHk6ZnVuY3Rpb24oKXtyZXR1cm4gYS5pc1JlYWR5KCl9LGdldFBlbmRpbmdSZXF1ZXN0czpmdW5jdGlvbigpe3JldHVybiBnfSxnZXRMb2FkaW5nUmVxdWVzdHM6ZnVuY3Rpb24oKXtyZXR1cm4gaH0sZ2V0TG9hZGluZ1RpbWU6ZnVuY3Rpb24oKXt2YXIgYSxiLGM9MDtmb3IoYj1mLmxlbmd0aC0xO2I+PTA7Yi09MSlpZihhPWZbYl0sYS5yZXF1ZXN0RW5kRGF0ZSBpbnN0YW5jZW9mIERhdGUmJmEuZmlyc3RCeXRlRGF0ZSBpbnN0YW5jZW9mIERhdGUpe2M9YS5yZXF1ZXN0RW5kRGF0ZS5nZXRUaW1lKCktYS5maXJzdEJ5dGVEYXRlLmdldFRpbWUoKTticmVha31yZXR1cm4gY30sZ2V0RXhlY3V0ZWRSZXF1ZXN0Rm9yVGltZTpmdW5jdGlvbihhKXt2YXIgYixjPWYubGVuZ3RoLTEsZD0wLzAsZT0wLzAsZz1udWxsO2ZvcihiPWM7Yj49MDtiLT0xKWlmKGc9ZltiXSxkPWcuc3RhcnRUaW1lLGU9ZCtnLmR1cmF0aW9uLCFpc05hTihkKSYmIWlzTmFOKGUpJiZhPmQmJmU+YSlyZXR1cm4gZztyZXR1cm4gbnVsbH0scmVtb3ZlRXhlY3V0ZWRSZXF1ZXN0OmZ1bmN0aW9uKGEpe20uY2FsbCh0aGlzLGEpfSxyZW1vdmVFeGVjdXRlZFJlcXVlc3RzQmVmb3JlVGltZTpmdW5jdGlvbihhKXt2YXIgYixjPWYubGVuZ3RoLTEsZD0wLzAsZT1udWxsO2ZvcihiPWM7Yj49MDtiLT0xKWU9ZltiXSxkPWUuc3RhcnRUaW1lLCFpc05hTihkKSYmYT5kJiZtLmNhbGwodGhpcyxlKX0sY2FuY2VsUGVuZGluZ1JlcXVlc3RzOmZ1bmN0aW9uKCl7Zz1bXX0sYWJvcnRSZXF1ZXN0czpmdW5jdGlvbigpe3RoaXMuZnJhZ21lbnRMb2FkZXIuYWJvcnQoKSxoPVtdfSxleGVjdXRlQ3VycmVudFJlcXVlc3Q6ZnVuY3Rpb24oKXt2YXIgYixjPXRoaXM7aWYoMCE9PWcubGVuZ3RoJiYhKGgubGVuZ3RoPj1pKSlzd2l0Y2goYj1nLnNoaWZ0KCksYi5hY3Rpb24pe2Nhc2VcImNvbXBsZXRlXCI6Zi5wdXNoKGIpLGUuY2FsbChhLGIpO2JyZWFrO2Nhc2VcImRvd25sb2FkXCI6aC5wdXNoKGIpLGouY2FsbChjLGIpO2JyZWFrO2RlZmF1bHQ6dGhpcy5kZWJ1Zy5sb2coXCJVbmtub3duIHJlcXVlc3QgYWN0aW9uLlwiKX19fX0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLkZyYWdtZW50TW9kZWwucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuRnJhZ21lbnRNb2RlbH0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLk1hbmlmZXN0TG9hZGVyPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGE9MyxiPTUwMCxjPW51bGwsZD1mdW5jdGlvbihhKXt2YXIgYj1udWxsO3JldHVybi0xIT09YS5pbmRleE9mKFwiL1wiKSYmKGI9YS5zdWJzdHJpbmcoMCxhLmxhc3RJbmRleE9mKFwiL1wiKSsxKSksYn0sZT1mdW5jdGlvbihhLGYpe3ZhciBnPWQoYSksaD1uZXcgWE1MSHR0cFJlcXVlc3QsaT1uZXcgRGF0ZSxqPSEwLGs9dGhpczt0aGlzLmRlYnVnLmxvZyhcIlN0YXJ0IGxvYWRpbmcgbWFuaWZlc3Q6IFwiK2EpLGgub3BlbihcIkdFVFwiLGEsITApLGgub25sb2FkPWZ1bmN0aW9uKCl7aC5zdGF0dXM8MjAwfHxoLnN0YXR1cz4yOTl8fChqPSExLGsubWV0cmljc01vZGVsLmFkZEh0dHBSZXF1ZXN0KFwic3RyZWFtXCIsbnVsbCxcIk1QRFwiLGEsbnVsbCxudWxsLGksbmV3IERhdGUsaC5zdGF0dXMsbnVsbCxudWxsKSxrLnBhcnNlci5wYXJzZShoLnJlc3BvbnNlVGV4dCxnKS50aGVuKGZ1bmN0aW9uKGIpe2IubXBkVXJsPWEsYy5yZXNvbHZlKGIpfSxmdW5jdGlvbigpe2MucmVqZWN0KGgpfSkpfSxoLm9ubG9hZGVuZD1oLm9uZXJyb3I9ZnVuY3Rpb24oKXtqJiYoaj0hMSxrLm1ldHJpY3NNb2RlbC5hZGRIdHRwUmVxdWVzdChcInN0cmVhbVwiLG51bGwsXCJNUERcIixhLG51bGwsbnVsbCxpLG5ldyBEYXRlLGguc3RhdHVzLG51bGwsbnVsbCksZj4wPyhrLmRlYnVnLmxvZyhcIkZhaWxlZCBsb2FkaW5nIG1hbmlmZXN0OiBcIithK1wiLCByZXRyeSBpbiBcIitiK1wibXNcIitcIiBhdHRlbXB0czogXCIrZiksZi0tLHNldFRpbWVvdXQoZnVuY3Rpb24oKXtlLmNhbGwoayxhLGYpfSxiKSk6KGsuZGVidWcubG9nKFwiRmFpbGVkIGxvYWRpbmcgbWFuaWZlc3Q6IFwiK2ErXCIgbm8gcmV0cnkgYXR0ZW1wdHMgbGVmdFwiKSxrLmVyckhhbmRsZXIuZG93bmxvYWRFcnJvcihcIm1hbmlmZXN0XCIsYSxoKSxjLnJlamVjdChoKSkpfSxoLnNlbmQoKX07cmV0dXJue2RlYnVnOnZvaWQgMCxwYXJzZXI6dm9pZCAwLGVyckhhbmRsZXI6dm9pZCAwLG1ldHJpY3NNb2RlbDp2b2lkIDAsbG9hZDpmdW5jdGlvbihiKXtyZXR1cm4gYz1RLmRlZmVyKCksZS5jYWxsKHRoaXMsYixhKSxjLnByb21pc2V9fX0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLk1hbmlmZXN0TG9hZGVyLnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLk1hbmlmZXN0TG9hZGVyfSxNZWRpYVBsYXllci5tb2RlbHMuTWFuaWZlc3RNb2RlbD1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3ZhciBhO3JldHVybntnZXRWYWx1ZTpmdW5jdGlvbigpe3JldHVybiBhfSxzZXRWYWx1ZTpmdW5jdGlvbihiKXthPWJ9fX0sTWVkaWFQbGF5ZXIubW9kZWxzLk1hbmlmZXN0TW9kZWwucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci5tb2RlbHMuTWFuaWZlc3RNb2RlbH0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLk1hbmlmZXN0VXBkYXRlcj1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3ZhciBhPTAvMCxiPW51bGwsYz1udWxsLGQ9ZnVuY3Rpb24oKXtudWxsIT09YiYmKGNsZWFySW50ZXJ2YWwoYiksYj1udWxsKX0sZT1mdW5jdGlvbigpe2QuY2FsbCh0aGlzKSxpc05hTihhKXx8KHRoaXMuZGVidWcubG9nKFwiUmVmcmVzaCBtYW5pZmVzdCBpbiBcIithK1wiIHNlY29uZHMuXCIpLGI9c2V0SW50ZXJ2YWwoYy5iaW5kKHRoaXMpLDFlMyphLHRoaXMpKX0sZj1mdW5jdGlvbigpe3ZhciBiPXRoaXMsYz1iLm1hbmlmZXN0TW9kZWwuZ2V0VmFsdWUoKTt2b2lkIDAhPT1jJiZudWxsIT09YyYmYi5tYW5pZmVzdEV4dC5nZXRSZWZyZXNoRGVsYXkoYykudGhlbihmdW5jdGlvbihjKXthPWMsZS5jYWxsKGIpfSl9O3JldHVybiBjPWZ1bmN0aW9uKCl7dmFyIGE9dGhpcyxiPWEubWFuaWZlc3RNb2RlbC5nZXRWYWx1ZSgpLGM9Yi5tcGRVcmw7Yi5oYXNPd25Qcm9wZXJ0eShcIkxvY2F0aW9uXCIpJiYoYz1iLkxvY2F0aW9uKSxhLmRlYnVnLmxvZyhcIlJlZnJlc2ggbWFuaWZlc3QgQCBcIitjKSxhLm1hbmlmZXN0TG9hZGVyLmxvYWQoYykudGhlbihmdW5jdGlvbihiKXthLm1hbmlmZXN0TW9kZWwuc2V0VmFsdWUoYiksYS5kZWJ1Zy5sb2coXCJNYW5pZmVzdCBoYXMgYmVlbiByZWZyZXNoZWQuXCIpLGEuZGVidWcubG9nKGIpLGYuY2FsbChhKSxhLnN5c3RlbS5ub3RpZnkoXCJtYW5pZmVzdFVwZGF0ZWRcIil9KX0se2RlYnVnOnZvaWQgMCxzeXN0ZW06dm9pZCAwLG1hbmlmZXN0TW9kZWw6dm9pZCAwLG1hbmlmZXN0RXh0OnZvaWQgMCxtYW5pZmVzdExvYWRlcjp2b2lkIDAsc2V0dXA6ZnVuY3Rpb24oKXtmLmNhbGwodGhpcyl9LGluaXQ6ZnVuY3Rpb24oKXtmLmNhbGwodGhpcyl9LHN0b3A6ZnVuY3Rpb24oKXtkLmNhbGwodGhpcyl9fX0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLk1hbmlmZXN0VXBkYXRlci5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOk1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5NYW5pZmVzdFVwZGF0ZXJ9LE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5NZWRpYVNvdXJjZUV4dGVuc2lvbnM9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIn0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLk1lZGlhU291cmNlRXh0ZW5zaW9ucy5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOk1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5NZWRpYVNvdXJjZUV4dGVuc2lvbnMsY3JlYXRlTWVkaWFTb3VyY2U6ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt2YXIgYT1cIldlYktpdE1lZGlhU291cmNlXCJpbiB3aW5kb3csYj1cIk1lZGlhU291cmNlXCJpbiB3aW5kb3c7cmV0dXJuIGI/US53aGVuKG5ldyBNZWRpYVNvdXJjZSk6YT9RLndoZW4obmV3IFdlYktpdE1lZGlhU291cmNlKTpudWxsfSxhdHRhY2hNZWRpYVNvdXJjZTpmdW5jdGlvbihhLGIpe1widXNlIHN0cmljdFwiO3JldHVybiBiLnNldFNvdXJjZSh3aW5kb3cuVVJMLmNyZWF0ZU9iamVjdFVSTChhKSksUS53aGVuKCEwKX0sZGV0YWNoTWVkaWFTb3VyY2U6ZnVuY3Rpb24oYSl7XCJ1c2Ugc3RyaWN0XCI7cmV0dXJuIGEuc2V0U291cmNlKFwiXCIpLFEud2hlbighMCl9LHNldER1cmF0aW9uOmZ1bmN0aW9uKGEsYil7XCJ1c2Ugc3RyaWN0XCI7cmV0dXJuIGEuZHVyYXRpb249YixRLndoZW4oYS5kdXJhdGlvbil9LHNpZ25hbEVuZE9mU3RyZWFtOmZ1bmN0aW9uKGEpe1widXNlIHN0cmljdFwiO3JldHVybiBhLmVuZE9mU3RyZWFtKCksUS53aGVuKCEwKX19LE1lZGlhUGxheWVyLm1vZGVscy5NZXRyaWNzTW9kZWw9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjtyZXR1cm57c3lzdGVtOnZvaWQgMCxzdHJlYW1NZXRyaWNzOnt9LGNsZWFyQ3VycmVudE1ldHJpY3NGb3JUeXBlOmZ1bmN0aW9uKGEpe2RlbGV0ZSB0aGlzLnN0cmVhbU1ldHJpY3NbYV19LGNsZWFyQWxsQ3VycmVudE1ldHJpY3M6ZnVuY3Rpb24oKXt0aGlzLnN0cmVhbU1ldHJpY3M9e319LGdldFJlYWRPbmx5TWV0cmljc0ZvcjpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5zdHJlYW1NZXRyaWNzLmhhc093blByb3BlcnR5KGEpP3RoaXMuc3RyZWFtTWV0cmljc1thXTpudWxsfSxnZXRNZXRyaWNzRm9yOmZ1bmN0aW9uKGEpe3ZhciBiO3JldHVybiB0aGlzLnN0cmVhbU1ldHJpY3MuaGFzT3duUHJvcGVydHkoYSk/Yj10aGlzLnN0cmVhbU1ldHJpY3NbYV06KGI9dGhpcy5zeXN0ZW0uZ2V0T2JqZWN0KFwibWV0cmljc1wiKSx0aGlzLnN0cmVhbU1ldHJpY3NbYV09YiksYn0sYWRkVGNwQ29ubmVjdGlvbjpmdW5jdGlvbihhLGIsYyxkLGUsZil7dmFyIGc9bmV3IE1lZGlhUGxheWVyLnZvLm1ldHJpY3MuVENQQ29ubmVjdGlvbjtyZXR1cm4gZy50Y3BpZD1iLGcuZGVzdD1jLGcudG9wZW49ZCxnLnRjbG9zZT1lLGcudGNvbm5lY3Q9Zix0aGlzLmdldE1ldHJpY3NGb3IoYSkuVGNwTGlzdC5wdXNoKGcpLGd9LGFkZEh0dHBSZXF1ZXN0OmZ1bmN0aW9uKGEsYixjLGQsZSxmLGcsaCxpLGosayxsKXt2YXIgbT1uZXcgTWVkaWFQbGF5ZXIudm8ubWV0cmljcy5IVFRQUmVxdWVzdDtyZXR1cm4gbS50Y3BpZD1iLG0udHlwZT1jLG0udXJsPWQsbS5hY3R1YWx1cmw9ZSxtLnJhbmdlPWYsbS50cmVxdWVzdD1nLG0udHJlc3BvbnNlPWgsbS50ZmluaXNoPWksbS5yZXNwb25zZWNvZGU9aixtLmludGVydmFsPWssbS5tZWRpYWR1cmF0aW9uPWwsdGhpcy5nZXRNZXRyaWNzRm9yKGEpLkh0dHBMaXN0LnB1c2gobSksbX0sYXBwZW5kSHR0cFRyYWNlOmZ1bmN0aW9uKGEsYixjLGQpe3ZhciBlPW5ldyBNZWRpYVBsYXllci52by5tZXRyaWNzLkhUVFBSZXF1ZXN0LlRyYWNlO3JldHVybiBlLnM9YixlLmQ9YyxlLmI9ZCxhLnRyYWNlLnB1c2goZSksZX0sYWRkUmVwcmVzZW50YXRpb25Td2l0Y2g6ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgZj1uZXcgTWVkaWFQbGF5ZXIudm8ubWV0cmljcy5SZXByZXNlbnRhdGlvblN3aXRjaDtyZXR1cm4gZi50PWIsZi5tdD1jLGYudG89ZCxmLmx0bz1lLHRoaXMuZ2V0TWV0cmljc0ZvcihhKS5SZXBTd2l0Y2hMaXN0LnB1c2goZiksZn0sYWRkQnVmZmVyTGV2ZWw6ZnVuY3Rpb24oYSxiLGMpe3ZhciBkPW5ldyBNZWRpYVBsYXllci52by5tZXRyaWNzLkJ1ZmZlckxldmVsO3JldHVybiBkLnQ9YixkLmxldmVsPWMsdGhpcy5nZXRNZXRyaWNzRm9yKGEpLkJ1ZmZlckxldmVsLnB1c2goZCksZH0sYWRkUGxheUxpc3Q6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIGU9bmV3IE1lZGlhUGxheWVyLnZvLm1ldHJpY3MuUGxheUxpc3Q7cmV0dXJuIGUuc3RhcnQ9YixlLm1zdGFydD1jLGUuc3RhcnR0eXBlPWQsdGhpcy5nZXRNZXRyaWNzRm9yKGEpLlBsYXlMaXN0LnB1c2goZSksZX0sYXBwZW5kUGxheUxpc3RUcmFjZTpmdW5jdGlvbihhLGIsYyxkLGUsZixnLGgpe3ZhciBpPW5ldyBNZWRpYVBsYXllci52by5tZXRyaWNzLlBsYXlMaXN0LlRyYWNlO3JldHVybiBpLnJlcHJlc2VudGF0aW9uaWQ9YixpLnN1YnJlcGxldmVsPWMsaS5zdGFydD1kLGkubXN0YXJ0PWUsaS5kdXJhdGlvbj1mLGkucGxheWJhY2tzcGVlZD1nLGkuc3RvcHJlYXNvbj1oLGEudHJhY2UucHVzaChpKSxpfX19LE1lZGlhUGxheWVyLm1vZGVscy5NZXRyaWNzTW9kZWwucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci5tb2RlbHMuTWV0cmljc01vZGVsfSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuUHJvdGVjdGlvbkNvbnRyb2xsZXI9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt2YXIgYT1udWxsLGI9bnVsbCxjPWZ1bmN0aW9uKGEpe3ZhciBiPXRoaXM7Yi5wcm90ZWN0aW9uTW9kZWwucmVtb3ZlS2V5U3lzdGVtKGEpfSxkPWZ1bmN0aW9uKGEsYyl7Zm9yKHZhciBkPXRoaXMsZT0wO2U8Yi5sZW5ndGg7KytlKWZvcih2YXIgZj0wO2Y8Yy5sZW5ndGg7KytmKWlmKGJbZV0uaXNTdXBwb3J0ZWQoY1tmXSkmJmQucHJvdGVjdGlvbkV4dC5zdXBwb3J0c0NvZGVjKGJbZV0ua2V5c1R5cGVTdHJpbmcsYSkpe3ZhciBnPWQubWFuaWZlc3RFeHQuZ2V0S0lEKGNbZl0pO3JldHVybiBnfHwoZz1cInVua25vd25cIiksZC5wcm90ZWN0aW9uTW9kZWwuYWRkS2V5U3lzdGVtKGcsY1tmXSxiW2VdKSxkLmRlYnVnLmxvZyhcIkRSTTogU2VsZWN0ZWQgS2V5IFN5c3RlbTogXCIrYltlXS5rZXlzVHlwZVN0cmluZytcIiBGb3IgS0lEOiBcIitnKSxnfXRocm93IG5ldyBFcnJvcihcIkRSTTogVGhlIHByb3RlY3Rpb24gc3lzdGVtIGZvciB0aGlzIGNvbnRlbnQgaXMgbm90IHN1cHBvcnRlZC5cIil9LGU9ZnVuY3Rpb24oYSxiLGMpe3ZhciBkPXRoaXMsZT1udWxsLGY9bnVsbDtkLnByb3RlY3Rpb25Nb2RlbC5uZWVkVG9BZGRLZXlTZXNzaW9uKGEpJiYoZj1kLnByb3RlY3Rpb25Nb2RlbC5nZXRJbml0RGF0YShhKSwhZiYmYz8oZj1jLGQuZGVidWcubG9nKFwiRFJNOiBVc2luZyBpbml0ZGF0YSBmcm9tIG5lZWRza2V5IGV2ZW50LiBsZW5ndGg6IFwiK2YubGVuZ3RoKSk6ZiYmZC5kZWJ1Zy5sb2coXCJEUk06IFVzaW5nIGluaXRkYXRhIGZyb20gcHJoZWFkZXIgaW4gbXBkLiBsZW5ndGg6IFwiK2YubGVuZ3RoKSxmPyhlPWQucHJvdGVjdGlvbk1vZGVsLmFkZEtleVNlc3Npb24oYSxiLGYpLGQuZGVidWcubG9nKFwiRFJNOiBBZGRlZCBLZXkgU2Vzc2lvbiBbXCIrZS5zZXNzaW9uSWQrXCJdIGZvciBLSUQ6IFwiK2ErXCIgdHlwZTogXCIrYitcIiBpbml0RGF0YSBsZW5ndGg6IFwiK2YubGVuZ3RoKSk6ZC5kZWJ1Zy5sb2coXCJEUk06IGluaXRkYXRhIGlzIG51bGwuXCIpKX0sZj1mdW5jdGlvbihhLGIsYyxkKXt2YXIgZSxmPXRoaXM7cmV0dXJuIGU9Zi5wcm90ZWN0aW9uTW9kZWwudXBkYXRlRnJvbU1lc3NhZ2UoYSxjLGQpLGUudGhlbihmdW5jdGlvbihhKXtiLnVwZGF0ZShhKX0pLGV9O3JldHVybntzeXN0ZW06dm9pZCAwLGRlYnVnOnZvaWQgMCxtYW5pZmVzdEV4dDp2b2lkIDAsY2FwYWJpbGl0aWVzOnZvaWQgMCx2aWRlb01vZGVsOnZvaWQgMCxwcm90ZWN0aW9uTW9kZWw6dm9pZCAwLHByb3RlY3Rpb25FeHQ6dm9pZCAwLHNldHVwOmZ1bmN0aW9uKCl7Yj10aGlzLnByb3RlY3Rpb25FeHQuZ2V0S2V5U3lzdGVtcygpfSxpbml0OmZ1bmN0aW9uKGIsYyl7dGhpcy52aWRlb01vZGVsPWIsdGhpcy5wcm90ZWN0aW9uTW9kZWw9YyxhPXRoaXMudmlkZW9Nb2RlbC5nZXRFbGVtZW50KClcclxufSxzZWxlY3RLZXlTeXN0ZW06ZCxlbnN1cmVLZXlTZXNzaW9uOmUsdXBkYXRlRnJvbU1lc3NhZ2U6Zix0ZWFyZG93bktleVN5c3RlbTpjfX0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlByb3RlY3Rpb25Db250cm9sbGVyLnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlByb3RlY3Rpb25Db250cm9sbGVyfSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuUHJvdGVjdGlvbkV4dGVuc2lvbnM9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIn0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlByb3RlY3Rpb25FeHRlbnNpb25zLnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlByb3RlY3Rpb25FeHRlbnNpb25zLHN1cHBvcnRzQ29kZWM6ZnVuY3Rpb24oYSxiKXtcInVzZSBzdHJpY3RcIjt2YXIgYz1cIldlYktpdE1lZGlhS2V5c1wiaW4gd2luZG93LGQ9XCJNU01lZGlhS2V5c1wiaW4gd2luZG93LGU9XCJNZWRpYUtleXNcImluIHdpbmRvdztyZXR1cm4gZT9NZWRpYUtleXMuaXNUeXBlU3VwcG9ydGVkKGEsYik6Yz9XZWJLaXRNZWRpYUtleXMuaXNUeXBlU3VwcG9ydGVkKGEsYik6ZD9NU01lZGlhS2V5cy5pc1R5cGVTdXBwb3J0ZWQoYSxiKTohMX0sY3JlYXRlTWVkaWFLZXlzOmZ1bmN0aW9uKGEpe1widXNlIHN0cmljdFwiO3ZhciBiPVwiV2ViS2l0TWVkaWFLZXlzXCJpbiB3aW5kb3csYz1cIk1TTWVkaWFLZXlzXCJpbiB3aW5kb3csZD1cIk1lZGlhS2V5c1wiaW4gd2luZG93O3JldHVybiBkP25ldyBNZWRpYUtleXMoYSk6Yj9uZXcgV2ViS2l0TWVkaWFLZXlzKGEpOmM/bmV3IE1TTWVkaWFLZXlzKGEpOm51bGx9LHNldE1lZGlhS2V5OmZ1bmN0aW9uKGEsYil7dmFyIGM9XCJXZWJLaXRTZXRNZWRpYUtleXNcImluIGEsZD1cIm1zU2V0TWVkaWFLZXlzXCJpbiBhLGU9XCJTZXRNZWRpYUtleXNcImluIGE7cmV0dXJuIGU/YS5TZXRNZWRpYUtleXMoYik6Yz9hLldlYktpdFNldE1lZGlhS2V5cyhiKTpkP2EubXNTZXRNZWRpYUtleXMoYik6KHRoaXMuZGVidWcubG9nKFwibm8gc2V0bWVkaWFrZXlzIGZ1bmN0aW9uIGluIGVsZW1lbnRcIiksdm9pZCAwKX0sY3JlYXRlU2Vzc2lvbjpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIGEuY3JlYXRlU2Vzc2lvbihiLGMpfSxnZXRLZXlTeXN0ZW1zOmZ1bmN0aW9uKCl7dmFyIGE9ZnVuY3Rpb24oYSxiKXt2YXIgYz1RLmRlZmVyKCksZD1udWxsLGU9W10sZj1uZXcgRE9NUGFyc2VyLGc9Zi5wYXJzZUZyb21TdHJpbmcoYSxcImFwcGxpY2F0aW9uL3htbFwiKTtpZighZy5nZXRFbGVtZW50c0J5VGFnTmFtZShcIkNoYWxsZW5nZVwiKVswXSlyZXR1cm4gYy5yZWplY3QoXCJEUk06IHBsYXlyZWFkeSB1cGRhdGUsIGNhbiBub3QgZmluZCBDaGFsbGVuZ2UgaW4ga2V5TWVzc2FnZVwiKSxjLnByb21pc2U7dmFyIGg9Zy5nZXRFbGVtZW50c0J5VGFnTmFtZShcIkNoYWxsZW5nZVwiKVswXS5jaGlsZE5vZGVzWzBdLm5vZGVWYWx1ZTtoJiYoZD1CQVNFNjQuZGVjb2RlKGgpKTt2YXIgaT1nLmdldEVsZW1lbnRzQnlUYWdOYW1lKFwibmFtZVwiKSxqPWcuZ2V0RWxlbWVudHNCeVRhZ05hbWUoXCJ2YWx1ZVwiKTtpZihpLmxlbmd0aCE9ai5sZW5ndGgpcmV0dXJuIGMucmVqZWN0KFwiRFJNOiBwbGF5cmVhZHkgdXBkYXRlLCBpbnZhbGlkIGhlYWRlciBuYW1lL3ZhbHVlIHBhaXIgaW4ga2V5TWVzc2FnZVwiKSxjLnByb21pc2U7Zm9yKHZhciBrPTA7azxpLmxlbmd0aDtrKyspZVtrXT17bmFtZTppW2tdLmNoaWxkTm9kZXNbMF0ubm9kZVZhbHVlLHZhbHVlOmpba10uY2hpbGROb2Rlc1swXS5ub2RlVmFsdWV9O3ZhciBsPW5ldyBYTUxIdHRwUmVxdWVzdDtyZXR1cm4gbC5vbmxvYWQ9ZnVuY3Rpb24oKXsyMDA9PWwuc3RhdHVzP2MucmVzb2x2ZShuZXcgVWludDhBcnJheShsLnJlc3BvbnNlKSk6Yy5yZWplY3QoJ0RSTTogcGxheXJlYWR5IHVwZGF0ZSwgWEhSIHN0YXR1cyBpcyBcIicrbC5zdGF0dXNUZXh0KydcIiAoJytsLnN0YXR1cytcIiksIGV4cGVjdGVkIHRvIGJlIDIwMC4gcmVhZHlTdGF0ZSBpcyBcIitsLnJlYWR5U3RhdGUpfSxsLm9uYWJvcnQ9ZnVuY3Rpb24oKXtjLnJlamVjdCgnRFJNOiBwbGF5cmVhZHkgdXBkYXRlLCBYSFIgYWJvcnRlZC4gc3RhdHVzIGlzIFwiJytsLnN0YXR1c1RleHQrJ1wiICgnK2wuc3RhdHVzK1wiKSwgcmVhZHlTdGF0ZSBpcyBcIitsLnJlYWR5U3RhdGUpfSxsLm9uZXJyb3I9ZnVuY3Rpb24oKXtjLnJlamVjdCgnRFJNOiBwbGF5cmVhZHkgdXBkYXRlLCBYSFIgZXJyb3IuIHN0YXR1cyBpcyBcIicrbC5zdGF0dXNUZXh0KydcIiAoJytsLnN0YXR1cytcIiksIHJlYWR5U3RhdGUgaXMgXCIrbC5yZWFkeVN0YXRlKX0sbC5vcGVuKFwiUE9TVFwiLGIpLGwucmVzcG9uc2VUeXBlPVwiYXJyYXlidWZmZXJcIixlJiZlLmZvckVhY2goZnVuY3Rpb24oYSl7bC5zZXRSZXF1ZXN0SGVhZGVyKGEubmFtZSxhLnZhbHVlKX0pLGwuc2VuZChkKSxjLnByb21pc2V9LGI9ZnVuY3Rpb24oYSxiKXtyZXR1cm4gbnVsbD09PWEmJjA9PT1iLmxlbmd0aH0sYz1mdW5jdGlvbihhKXt2YXIgYj0wLGM9MCxkPTAsZT1uZXcgVWludDhBcnJheShbMTEyLDExNSwxMTUsMTA0LDAsMCwwLDBdKSxmPW5ldyBVaW50OEFycmF5KFsxNTQsNCwyNDAsMTIxLDE1Miw2NCw2NiwxMzQsMTcxLDE0NiwyMzAsOTEsMjI0LDEzNiw5NSwxNDldKSxnPW51bGwsaD1udWxsLGk9bnVsbCxqPW51bGw7aWYoXCJwcm9cImluIGEpZz1CQVNFNjQuZGVjb2RlQXJyYXkoYS5wcm8uX190ZXh0KTtlbHNle2lmKCEoXCJwcmhlYWRlclwiaW4gYSkpcmV0dXJuIG51bGw7Zz1CQVNFNjQuZGVjb2RlQXJyYXkoYS5wcmhlYWRlci5fX3RleHQpfXJldHVybiBjPWcubGVuZ3RoLGQ9NCtlLmxlbmd0aCtmLmxlbmd0aCs0K2MsaD1uZXcgQXJyYXlCdWZmZXIoZCksaT1uZXcgVWludDhBcnJheShoKSxqPW5ldyBEYXRhVmlldyhoKSxqLnNldFVpbnQzMihiLGQpLGIrPTQsaS5zZXQoZSxiKSxiKz1lLmxlbmd0aCxpLnNldChmLGIpLGIrPWYubGVuZ3RoLGouc2V0VWludDMyKGIsYyksYis9NCxpLnNldChnLGIpLGIrPWMsaX07cmV0dXJuW3tzY2hlbWVJZFVyaTpcInVybjp1dWlkOjlhMDRmMDc5LTk4NDAtNDI4Ni1hYjkyLWU2NWJlMDg4NWY5NVwiLGtleXNUeXBlU3RyaW5nOlwiY29tLm1pY3Jvc29mdC5wbGF5cmVhZHlcIixpc1N1cHBvcnRlZDpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5zY2hlbWVJZFVyaT09PWEuc2NoZW1lSWRVcmkudG9Mb3dlckNhc2UoKX0sbmVlZFRvQWRkS2V5U2Vzc2lvbjpiLGdldEluaXREYXRhOmMsZ2V0VXBkYXRlOmF9LHtzY2hlbWVJZFVyaTpcInVybjptcGVnOmRhc2g6bXA0cHJvdGVjdGlvbjoyMDExXCIsa2V5c1R5cGVTdHJpbmc6XCJjb20ubWljcm9zb2Z0LnBsYXlyZWFkeVwiLGlzU3VwcG9ydGVkOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLnNjaGVtZUlkVXJpPT09YS5zY2hlbWVJZFVyaS50b0xvd2VyQ2FzZSgpJiZcImNlbmNcIj09PWEudmFsdWUudG9Mb3dlckNhc2UoKX0sbmVlZFRvQWRkS2V5U2Vzc2lvbjpiLGdldEluaXREYXRhOmZ1bmN0aW9uKCl7cmV0dXJuIG51bGx9LGdldFVwZGF0ZTphfSx7c2NoZW1lSWRVcmk6XCJ1cm46dXVpZDowMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDBcIixrZXlzVHlwZVN0cmluZzpcIndlYmtpdC1vcmcudzMuY2xlYXJrZXlcIixpc1N1cHBvcnRlZDpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5zY2hlbWVJZFVyaT09PWEuc2NoZW1lSWRVcmkudG9Mb3dlckNhc2UoKX0sbmVlZFRvQWRkS2V5U2Vzc2lvbjpmdW5jdGlvbigpe3JldHVybiEwfSxnZXRJbml0RGF0YTpmdW5jdGlvbigpe3JldHVybiBudWxsfSxnZXRVcGRhdGU6ZnVuY3Rpb24oYSl7cmV0dXJuIFEud2hlbihhKX19XX0sYWRkS2V5OmZ1bmN0aW9uKGEsYixjLGQsZSl7YS53ZWJraXRBZGRLZXkoYixjLGQsZSl9LGdlbmVyYXRlS2V5UmVxdWVzdDpmdW5jdGlvbihhLGIsYyl7YS53ZWJraXRHZW5lcmF0ZUtleVJlcXVlc3QoYixjKX0sbGlzdGVuVG9OZWVkS2V5OmZ1bmN0aW9uKGEsYil7YS5saXN0ZW4oXCJ3ZWJraXRuZWVka2V5XCIsYiksYS5saXN0ZW4oXCJtc25lZWRrZXlcIixiKSxhLmxpc3RlbihcIm5lZWRLZXlcIixiKX0sbGlzdGVuVG9LZXlFcnJvcjpmdW5jdGlvbihhLGIpe2EuYWRkRXZlbnRMaXN0ZW5lcihcIndlYmtpdGtleWVycm9yXCIsYiwhMSksYS5hZGRFdmVudExpc3RlbmVyKFwibXNrZXllcnJvclwiLGIsITEpLGEuYWRkRXZlbnRMaXN0ZW5lcihcImtleWVycm9yXCIsYiwhMSl9LGxpc3RlblRvS2V5TWVzc2FnZTpmdW5jdGlvbihhLGIpe2EuYWRkRXZlbnRMaXN0ZW5lcihcIndlYmtpdGtleW1lc3NhZ2VcIixiLCExKSxhLmFkZEV2ZW50TGlzdGVuZXIoXCJtc2tleW1lc3NhZ2VcIixiLCExKSxhLmFkZEV2ZW50TGlzdGVuZXIoXCJrZXltZXNzYWdlXCIsYiwhMSl9LGxpc3RlblRvS2V5QWRkZWQ6ZnVuY3Rpb24oYSxiKXthLmFkZEV2ZW50TGlzdGVuZXIoXCJ3ZWJraXRrZXlhZGRlZFwiLGIsITEpLGEuYWRkRXZlbnRMaXN0ZW5lcihcIm1za2V5YWRkZWRcIixiLCExKSxhLmFkZEV2ZW50TGlzdGVuZXIoXCJrZXlhZGRlZFwiLGIsITEpfSx1bmxpc3RlblRvS2V5RXJyb3I6ZnVuY3Rpb24oYSxiKXthLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJ3ZWJraXRrZXllcnJvclwiLGIpLGEucmVtb3ZlRXZlbnRMaXN0ZW5lcihcIm1za2V5ZXJyb3JcIixiKSxhLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJrZXllcnJvclwiLGIpfSx1bmxpc3RlblRvS2V5TWVzc2FnZTpmdW5jdGlvbihhLGIpe2EucmVtb3ZlRXZlbnRMaXN0ZW5lcihcIndlYmtpdGtleW1lc3NhZ2VcIixiKSxhLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJtc2tleW1lc3NhZ2VcIixiKSxhLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJrZXltZXNzYWdlXCIsYil9LHVubGlzdGVuVG9LZXlBZGRlZDpmdW5jdGlvbihhLGIpe2EucmVtb3ZlRXZlbnRMaXN0ZW5lcihcIndlYmtpdGtleWFkZGVkXCIsYiksYS5yZW1vdmVFdmVudExpc3RlbmVyKFwibXNrZXlhZGRlZFwiLGIpLGEucmVtb3ZlRXZlbnRMaXN0ZW5lcihcImtleWFkZGVkXCIsYil9fSxNZWRpYVBsYXllci5tb2RlbHMuUHJvdGVjdGlvbk1vZGVsPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGE9bnVsbCxiPW51bGwsYz1udWxsLGQ9bnVsbCxlPVtdO3JldHVybntzeXN0ZW06dm9pZCAwLHZpZGVvTW9kZWw6dm9pZCAwLHByb3RlY3Rpb25FeHQ6dm9pZCAwLHNldHVwOmZ1bmN0aW9uKCl7YT10aGlzLnZpZGVvTW9kZWwuZ2V0RWxlbWVudCgpfSxpbml0OmZ1bmN0aW9uKGIpe3RoaXMudmlkZW9Nb2RlbD1iLGE9dGhpcy52aWRlb01vZGVsLmdldEVsZW1lbnQoKX0sYWRkS2V5U2Vzc2lvbjpmdW5jdGlvbihhLGYsZyl7dmFyIGg9bnVsbDtyZXR1cm4gaD10aGlzLnByb3RlY3Rpb25FeHQuY3JlYXRlU2Vzc2lvbihlW2FdLmtleXMsZixnKSx0aGlzLnByb3RlY3Rpb25FeHQubGlzdGVuVG9LZXlBZGRlZChoLGIpLHRoaXMucHJvdGVjdGlvbkV4dC5saXN0ZW5Ub0tleUVycm9yKGgsYyksdGhpcy5wcm90ZWN0aW9uRXh0Lmxpc3RlblRvS2V5TWVzc2FnZShoLGQpLGVbYV0uaW5pdERhdGE9ZyxlW2FdLmtleVNlc3Npb25zLnB1c2goaCksaH0sYWRkS2V5U3lzdGVtOmZ1bmN0aW9uKGIsYyxkKXt2YXIgZj1udWxsO2Y9dGhpcy5wcm90ZWN0aW9uRXh0LmNyZWF0ZU1lZGlhS2V5cyhkLmtleXNUeXBlU3RyaW5nKSx0aGlzLnByb3RlY3Rpb25FeHQuc2V0TWVkaWFLZXkoYSxmKSxlW2JdPXtrSUQ6Yixjb250ZW50UHJvdGVjdGlvbjpjLGtleVN5c3RlbTpkLGtleXM6Zixpbml0RGF0YTpudWxsLGtleVNlc3Npb25zOltdfX0scmVtb3ZlS2V5U3lzdGVtOmZ1bmN0aW9uKGEpe2lmKG51bGwhPT1hJiZ2b2lkIDAhPT1lW2FdJiYwIT09ZVthXS5rZXlTZXNzaW9ucy5sZW5ndGgpe2Zvcih2YXIgZj1lW2FdLmtleVNlc3Npb25zLGc9MDtnPGYubGVuZ3RoOysrZyl0aGlzLnByb3RlY3Rpb25FeHQudW5saXN0ZW5Ub0tleUVycm9yKGZbZ10sYyksdGhpcy5wcm90ZWN0aW9uRXh0LnVubGlzdGVuVG9LZXlBZGRlZChmW2ddLGIpLHRoaXMucHJvdGVjdGlvbkV4dC51bmxpc3RlblRvS2V5TWVzc2FnZShmW2ddLGQpLGZbZ10uY2xvc2UoKTtlW2FdPXZvaWQgMH19LG5lZWRUb0FkZEtleVNlc3Npb246ZnVuY3Rpb24oYSl7dmFyIGI9bnVsbDtyZXR1cm4gYj1lW2FdLGIua2V5U3lzdGVtLm5lZWRUb0FkZEtleVNlc3Npb24oYi5pbml0RGF0YSxiLmtleVNlc3Npb25zKX0sZ2V0SW5pdERhdGE6ZnVuY3Rpb24oYSl7dmFyIGI9bnVsbDtyZXR1cm4gYj1lW2FdLGIua2V5U3lzdGVtLmdldEluaXREYXRhKGIuY29udGVudFByb3RlY3Rpb24pfSx1cGRhdGVGcm9tTWVzc2FnZTpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIGVbYV0ua2V5U3lzdGVtLmdldFVwZGF0ZShiLGMpfSxsaXN0ZW5Ub05lZWRLZXk6ZnVuY3Rpb24oYSl7dGhpcy5wcm90ZWN0aW9uRXh0Lmxpc3RlblRvTmVlZEtleSh0aGlzLnZpZGVvTW9kZWwsYSl9LGxpc3RlblRvS2V5RXJyb3I6ZnVuY3Rpb24oYSl7Yz1hO2Zvcih2YXIgYj0wO2I8ZS5sZW5ndGg7KytiKWZvcih2YXIgZD1lW2JdLmtleVNlc3Npb25zLGY9MDtmPGQubGVuZ3RoOysrZil0aGlzLnByb3RlY3Rpb25FeHQubGlzdGVuVG9LZXlFcnJvcihkW2ZdLGEpfSxsaXN0ZW5Ub0tleU1lc3NhZ2U6ZnVuY3Rpb24oYSl7ZD1hO2Zvcih2YXIgYj0wO2I8ZS5sZW5ndGg7KytiKWZvcih2YXIgYz1lW2JdLmtleVNlc3Npb25zLGY9MDtmPGMubGVuZ3RoOysrZil0aGlzLnByb3RlY3Rpb25FeHQubGlzdGVuVG9LZXlNZXNzYWdlKGNbZl0sYSl9LGxpc3RlblRvS2V5QWRkZWQ6ZnVuY3Rpb24oYSl7Yj1hO2Zvcih2YXIgYz0wO2M8ZS5sZW5ndGg7KytjKWZvcih2YXIgZD1lW2NdLmtleVNlc3Npb25zLGY9MDtmPGQubGVuZ3RoOysrZil0aGlzLnByb3RlY3Rpb25FeHQubGlzdGVuVG9LZXlBZGRlZChkW2ZdLGEpfX19LE1lZGlhUGxheWVyLm1vZGVscy5Qcm90ZWN0aW9uTW9kZWwucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci5tb2RlbHMuUHJvdGVjdGlvbk1vZGVsfSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuUmVxdWVzdFNjaGVkdWxlcj1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3ZhciBhPVtdLGI9bnVsbCxjPW51bGwsZD1mdW5jdGlvbihhLGIpe2lmKGEmJmIpe3ZhciBjPWcoYSk7Y3x8KGM9ZS5jYWxsKHRoaXMsYSkpLGMuc2V0SXNTY2hlZHVsZWQoITApLGMuc2V0U2NoZWR1bGVkVGFzayhiKSxqLmNhbGwodGhpcyksYi5jYWxsKGEpfX0sZT1mdW5jdGlvbihiKXtpZighYilyZXR1cm4gbnVsbDt2YXIgYz10aGlzLnN5c3RlbS5nZXRPYmplY3QoXCJzY2hlZHVsZXJNb2RlbFwiKTtyZXR1cm4gYy5zZXRDb250ZXh0KGIpLGEucHVzaChjKSxjfSxmPWZ1bmN0aW9uKGIpe3ZhciBjPWEuaW5kZXhPZihiKTstMSE9PWMmJmEuc3BsaWNlKGMsMSl9LGc9ZnVuY3Rpb24oYil7Zm9yKHZhciBjPTA7YzxhLmxlbmd0aDtjKyspaWYoYVtjXS5nZXRDb250ZXh0KCk9PT1iKXJldHVybiBhW2NdO3JldHVybiBudWxsfSxoPWZ1bmN0aW9uKCl7aS5jYWxsKHRoaXMpfSxpPWZ1bmN0aW9uKCl7Zm9yKHZhciBiLGM9MDtjPGEubGVuZ3RoO2MrKyliPWFbY10sYi5nZXRJc1NjaGVkdWxlZCgpJiZiLmV4ZWN1dGVTY2hlZHVsZWRUYXNrKCl9LGo9ZnVuY3Rpb24oKXtudWxsPT09YyYmKHRoaXMuYWRqdXN0RXhlY3V0ZUludGVydmFsKCksYz1zZXRJbnRlcnZhbChoLmJpbmQodGhpcyksYikpfSxrPWZ1bmN0aW9uKGIpe3ZhciBjPWcoYik7YyYmKGYoYyksMD09PWEubGVuZ3RoJiZsLmNhbGwodGhpcykpfSxsPWZ1bmN0aW9uKCl7Y2xlYXJJbnRlcnZhbChjKSxjPW51bGx9O3JldHVybntzeXN0ZW06dm9pZCAwLGRlYnVnOnZvaWQgMCxzY2hlZHVsZXJFeHQ6dm9pZCAwLGlzU2NoZWR1bGVkOmZ1bmN0aW9uKGEpe3ZhciBiPWcoYSk7cmV0dXJuISFiJiZiLmdldElzU2NoZWR1bGVkKCl9LGdldEV4ZWN1dGVJbnRlcnZhbDpmdW5jdGlvbigpe3JldHVybiBifSxhZGp1c3RFeGVjdXRlSW50ZXJ2YWw6ZnVuY3Rpb24oKXtpZighKGEubGVuZ3RoPDEpKXt2YXIgZD10aGlzLnNjaGVkdWxlckV4dC5nZXRFeGVjdXRlSW50ZXJ2YWwoYVswXS5nZXRDb250ZXh0KCkpO2IhPT1kJiYoYj1kLG51bGwhPT1jJiYodGhpcy5kZWJ1Zy5sb2coXCJDaGFuZ2luZyBleGVjdXRlIGludGVydmFsOiBcIitiKSxjbGVhckludGVydmFsKGMpLGM9c2V0SW50ZXJ2YWwoaC5iaW5kKHRoaXMpLGIpKSl9fSxzdGFydFNjaGVkdWxpbmc6ZCxzdG9wU2NoZWR1bGluZzprfX0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlJlcXVlc3RTY2hlZHVsZXIucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuUmVxdWVzdFNjaGVkdWxlcn0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlNjaGVkdWxlckV4dGVuc2lvbnM9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIn0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlNjaGVkdWxlckV4dGVuc2lvbnMucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuU2NoZWR1bGVyRXh0ZW5zaW9ucyxnZXRFeGVjdXRlSW50ZXJ2YWw6ZnVuY3Rpb24oYSl7dmFyIGI9MWUzO3JldHVyblwidW5kZWZpbmVkXCIhPXR5cGVvZiBhLmdldE1pbkJ1ZmZlclRpbWUmJihiPTFlMyphLmdldE1pbkJ1ZmZlclRpbWUoKS80LGI9TWF0aC5tYXgoYiwxZTMpKSxifX0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlNjaGVkdWxlck1vZGVsPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGEsYixjPSExO3JldHVybntzeXN0ZW06dm9pZCAwLGRlYnVnOnZvaWQgMCxzY2hlZHVsZXJFeHQ6dm9pZCAwLHNldENvbnRleHQ6ZnVuY3Rpb24oYil7YT1ifSxnZXRDb250ZXh0OmZ1bmN0aW9uKCl7cmV0dXJuIGF9LHNldFNjaGVkdWxlZFRhc2s6ZnVuY3Rpb24oYSl7Yj1hfSxleGVjdXRlU2NoZWR1bGVkVGFzazpmdW5jdGlvbigpe2IuY2FsbChhKX0sc2V0SXNTY2hlZHVsZWQ6ZnVuY3Rpb24oYSl7Yz1hfSxnZXRJc1NjaGVkdWxlZDpmdW5jdGlvbigpe3JldHVybiBjfX19LE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5TY2hlZHVsZXJNb2RlbC5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOk1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5TY2hlZHVsZXJNb2RlbH0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlNvdXJjZUJ1ZmZlckV4dGVuc2lvbnM9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt0aGlzLnN5c3RlbT12b2lkIDAsdGhpcy5tYW5pZmVzdEV4dD12b2lkIDB9LE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5Tb3VyY2VCdWZmZXJFeHRlbnNpb25zLnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlNvdXJjZUJ1ZmZlckV4dGVuc2lvbnMsY3JlYXRlU291cmNlQnVmZmVyOmZ1bmN0aW9uKGEsYil7XCJ1c2Ugc3RyaWN0XCI7dmFyIGM9US5kZWZlcigpLGQ9dGhpczt0cnl7Yy5yZXNvbHZlKGEuYWRkU291cmNlQnVmZmVyKGIpKX1jYXRjaChlKXtkLm1hbmlmZXN0RXh0LmdldElzVGV4dFRyYWNrKGIpP2MucmVzb2x2ZShkLnN5c3RlbS5nZXRPYmplY3QoXCJ0ZXh0VlRUU291cmNlQnVmZmVyXCIpKTpjLnJlamVjdChlLmRlc2NyaXB0aW9uKX1yZXR1cm4gYy5wcm9taXNlfSxyZW1vdmVTb3VyY2VCdWZmZXI6ZnVuY3Rpb24oYSxiKXtcInVzZSBzdHJpY3RcIjt2YXIgYz1RLmRlZmVyKCk7dHJ5e2MucmVzb2x2ZShhLnJlbW92ZVNvdXJjZUJ1ZmZlcihiKSl9Y2F0Y2goZCl7Yy5yZWplY3QoZC5kZXNjcmlwdGlvbil9cmV0dXJuIGMucHJvbWlzZX0sZ2V0QnVmZmVyUmFuZ2U6ZnVuY3Rpb24oYSxiLGMpe1widXNlIHN0cmljdFwiO3ZhciBkLGUsZj1udWxsLGc9MCxoPTAsaT1udWxsLGo9bnVsbCxrPTAsbD1jfHwuMTU7dHJ5e2Y9YS5idWZmZXJlZH1jYXRjaChtKXtyZXR1cm4gUS53aGVuKG51bGwpfWlmKG51bGwhPT1mKXtmb3IoZT0wLGQ9Zi5sZW5ndGg7ZD5lO2UrPTEpaWYoZz1mLnN0YXJ0KGUpLGg9Zi5lbmQoZSksbnVsbD09PWkpe2lmKGs9TWF0aC5hYnMoZy1iKSxiPj1nJiZoPmIpe2k9ZyxqPWg7Y29udGludWV9aWYobD49ayl7aT1nLGo9aDtjb250aW51ZX19ZWxzZXtpZihrPWctaiwhKGw+PWspKWJyZWFrO2o9aH1pZihudWxsIT09aSlyZXR1cm4gUS53aGVuKHtzdGFydDppLGVuZDpqfSl9cmV0dXJuIFEud2hlbihudWxsKX0sZ2V0QWxsUmFuZ2VzOmZ1bmN0aW9uKGEpe3ZhciBiPW51bGw7dHJ5e3JldHVybiBiPWEuYnVmZmVyZWQsUS53aGVuKGIpfWNhdGNoKGMpe3JldHVybiBRLndoZW4obnVsbCl9fSxnZXRCdWZmZXJMZW5ndGg6ZnVuY3Rpb24oYSxiLGMpe1widXNlIHN0cmljdFwiO3ZhciBkPXRoaXMsZT1RLmRlZmVyKCk7cmV0dXJuIGQuZ2V0QnVmZmVyUmFuZ2UoYSxiLGMpLnRoZW4oZnVuY3Rpb24oYSl7bnVsbD09PWE/ZS5yZXNvbHZlKDApOmUucmVzb2x2ZShhLmVuZC1iKX0pLGUucHJvbWlzZX0sd2FpdEZvclVwZGF0ZUVuZDpmdW5jdGlvbihhKXtcInVzZSBzdHJpY3RcIjt2YXIgYixjPVEuZGVmZXIoKSxkPTUwLGU9ZnVuY3Rpb24oKXthLnVwZGF0aW5nfHwoY2xlYXJJbnRlcnZhbChiKSxjLnJlc29sdmUoITApKX0sZj1mdW5jdGlvbigpe2EucmVtb3ZlRXZlbnRMaXN0ZW5lcihcInVwZGF0ZWVuZFwiLGYsITEpLGMucmVzb2x2ZSghMCl9O2lmKGEuaGFzT3duUHJvcGVydHkoXCJhZGRFdmVudExpc3RlbmVyXCIpKXRyeXthLmFkZEV2ZW50TGlzdGVuZXIoXCJ1cGRhdGVlbmRcIixmLCExKX1jYXRjaChnKXtiPXNldEludGVydmFsKGUsZCl9ZWxzZSBiPXNldEludGVydmFsKGUsZCk7cmV0dXJuIGMucHJvbWlzZX0sYXBwZW5kOmZ1bmN0aW9uKGEsYil7dmFyIGM9US5kZWZlcigpO3RyeXtcImFwcGVuZFwiaW4gYT9hLmFwcGVuZChiKTpcImFwcGVuZEJ1ZmZlclwiaW4gYSYmYS5hcHBlbmRCdWZmZXIoYiksdGhpcy53YWl0Rm9yVXBkYXRlRW5kKGEpLnRoZW4oZnVuY3Rpb24oKXtjLnJlc29sdmUoKX0pfWNhdGNoKGQpe2MucmVqZWN0KHtlcnI6ZCxkYXRhOmJ9KX1yZXR1cm4gYy5wcm9taXNlfSxyZW1vdmU6ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgZj1RLmRlZmVyKCk7dHJ5e2I+PTAmJmQ+YiYmYz5iJiZcImVuZGVkXCIhPT1lLnJlYWR5U3RhdGUmJmEucmVtb3ZlKGIsYyksdGhpcy53YWl0Rm9yVXBkYXRlRW5kKGEpLnRoZW4oZnVuY3Rpb24oKXtmLnJlc29sdmUoKX0pfWNhdGNoKGcpe2YucmVqZWN0KGcpfXJldHVybiBmLnByb21pc2V9LGFib3J0OmZ1bmN0aW9uKGEsYil7XCJ1c2Ugc3RyaWN0XCI7dmFyIGM9US5kZWZlcigpO3RyeXtcIm9wZW5cIj09PWEucmVhZHlTdGF0ZSYmYi5hYm9ydCgpLGMucmVzb2x2ZSgpfWNhdGNoKGQpe2MucmVqZWN0KGQuZGVzY3JpcHRpb24pfXJldHVybiBjLnByb21pc2V9fSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuU3RyZWFtPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGEsYixjLGQsZSxmLGcsaCxpLGosayxsLG0sbixvLHAscT1udWxsLHI9bnVsbCxzPW51bGwsdD1udWxsLHU9LTEsdj1udWxsLHc9LTEseD1udWxsLHk9LTEsej0hMCxBPSExLEI9ITEsQz1udWxsLEQ9W10sRT0tMSxGPW51bGwsRz1mdW5jdGlvbigpe3RoaXMuZGVidWcubG9nKFwiQXR0ZW1wdGluZyBwbGF5Li4uXCIpLEEmJih0aGlzLmRlYnVnLmxvZyhcIkRvIHBsYXkuXCIpLHRoaXMudmlkZW9Nb2RlbC5wbGF5KCkpfSxIPWZ1bmN0aW9uKCl7dGhpcy5kZWJ1Zy5sb2coXCJEbyBwYXVzZS5cIiksdGhpcy52aWRlb01vZGVsLnBhdXNlKCl9LEk9ZnVuY3Rpb24oYSl7dGhpcy5kZWJ1Zy5sb2coXCJBdHRlbXB0aW5nIHNlZWsuLi5cIiksQSYmKHRoaXMuZGVidWcubG9nKFwiRG8gc2VlazogXCIrYSksdGhpcy5zeXN0ZW0ubm90aWZ5KFwic2V0Q3VycmVudFRpbWVcIiksdGhpcy52aWRlb01vZGVsLnNldEN1cnJlbnRUaW1lKGEpLHQmJnQuc2VlayhhKSx2JiZ2LnNlZWsoYSkpfSxKPWZ1bmN0aW9uKGEpe3ZhciBiLGM9dGhpcztpZihiPVwibXNuZWVka2V5XCIhPT1hLnR5cGU/YS50eXBlOnEsRC5wdXNoKHt0eXBlOmIsaW5pdERhdGE6YS5pbml0RGF0YX0pLHRoaXMuZGVidWcubG9nKFwiRFJNOiBLZXkgcmVxdWlyZWQgZm9yIC0gXCIrYikscyYmcSYmIUMpdHJ5e0M9Yy5wcm90ZWN0aW9uQ29udHJvbGxlci5zZWxlY3RLZXlTeXN0ZW0ocSxzKX1jYXRjaChkKXtILmNhbGwoYyksYy5kZWJ1Zy5sb2coZCksYy5lcnJIYW5kbGVyLm1lZGlhS2V5U3lzdGVtU2VsZWN0aW9uRXJyb3IoZCl9QyYmYy5wcm90ZWN0aW9uQ29udHJvbGxlci5lbnN1cmVLZXlTZXNzaW9uKEMsYixhLmluaXREYXRhKX0sSz1mdW5jdGlvbihhKXt2YXIgYj10aGlzLGM9bnVsbCxkPW51bGwsZT1udWxsLGY9bnVsbDt0aGlzLmRlYnVnLmxvZyhcIkRSTTogR290IGEga2V5IG1lc3NhZ2UuLi5cIiksYz1hLnRhcmdldCxkPW5ldyBVaW50MTZBcnJheShhLm1lc3NhZ2UuYnVmZmVyKSxlPVN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCxkKSxmPWEuZGVzdGluYXRpb25VUkwsYi5wcm90ZWN0aW9uQ29udHJvbGxlci51cGRhdGVGcm9tTWVzc2FnZShDLGMsZSxmKS5mYWlsKGZ1bmN0aW9uKGEpe0guY2FsbChiKSxiLmRlYnVnLmxvZyhhKSxiLmVyckhhbmRsZXIubWVkaWFLZXlNZXNzYWdlRXJyb3IoYSl9KX0sTD1mdW5jdGlvbigpe3RoaXMuZGVidWcubG9nKFwiRFJNOiBLZXkgYWRkZWQuXCIpfSxNPWZ1bmN0aW9uKCl7dmFyIGEsYj1ldmVudC50YXJnZXQ7c3dpdGNoKGE9XCJEUk06IE1lZGlhS2V5RXJyb3IgLSBzZXNzaW9uSWQ6IFwiK2Iuc2Vzc2lvbklkK1wiIGVycm9yQ29kZTogXCIrYi5lcnJvci5jb2RlK1wiIHN5c3RlbUVycm9yQ29kZTogXCIrYi5lcnJvci5zeXN0ZW1Db2RlK1wiIFtcIixiLmVycm9yLmNvZGUpe2Nhc2UgMTphKz1cIk1FRElBX0tFWUVSUl9VTktOT1dOIC0gQW4gdW5zcGVjaWZpZWQgZXJyb3Igb2NjdXJyZWQuIFRoaXMgdmFsdWUgaXMgdXNlZCBmb3IgZXJyb3JzIHRoYXQgZG9uJ3QgbWF0Y2ggYW55IG9mIHRoZSBvdGhlciBjb2Rlcy5cIjticmVhaztjYXNlIDI6YSs9XCJNRURJQV9LRVlFUlJfQ0xJRU5UIC0gVGhlIEtleSBTeXN0ZW0gY291bGQgbm90IGJlIGluc3RhbGxlZCBvciB1cGRhdGVkLlwiO2JyZWFrO2Nhc2UgMzphKz1cIk1FRElBX0tFWUVSUl9TRVJWSUNFIC0gVGhlIG1lc3NhZ2UgcGFzc2VkIGludG8gdXBkYXRlIGluZGljYXRlZCBhbiBlcnJvciBmcm9tIHRoZSBsaWNlbnNlIHNlcnZpY2UuXCI7YnJlYWs7Y2FzZSA0OmErPVwiTUVESUFfS0VZRVJSX09VVFBVVCAtIFRoZXJlIGlzIG5vIGF2YWlsYWJsZSBvdXRwdXQgZGV2aWNlIHdpdGggdGhlIHJlcXVpcmVkIGNoYXJhY3RlcmlzdGljcyBmb3IgdGhlIGNvbnRlbnQgcHJvdGVjdGlvbiBzeXN0ZW0uXCI7YnJlYWs7Y2FzZSA1OmErPVwiTUVESUFfS0VZRVJSX0hBUkRXQVJFQ0hBTkdFIC0gQSBoYXJkd2FyZSBjb25maWd1cmF0aW9uIGNoYW5nZSBjYXVzZWQgYSBjb250ZW50IHByb3RlY3Rpb24gZXJyb3IuXCI7YnJlYWs7Y2FzZSA2OmErPVwiTUVESUFfS0VZRVJSX0RPTUFJTiAtIEFuIGVycm9yIG9jY3VycmVkIGluIGEgbXVsdGktZGV2aWNlIGRvbWFpbiBsaWNlbnNpbmcgY29uZmlndXJhdGlvbi4gVGhlIG1vc3QgY29tbW9uIGVycm9yIGlzIGEgZmFpbHVyZSB0byBqb2luIHRoZSBkb21haW4uXCJ9YSs9XCJdXCIsdGhpcy5kZWJ1Zy5sb2coYSksdGhpcy5lcnJIYW5kbGVyLm1lZGlhS2V5U2Vzc2lvbkVycm9yKGEpfSxOPWZ1bmN0aW9uKGEpe3ZhciBiPVEuZGVmZXIoKSxjPXRoaXMsZD1mdW5jdGlvbihlKXtjLmRlYnVnLmxvZyhcIk1lZGlhU291cmNlIGlzIG9wZW4hXCIpLGMuZGVidWcubG9nKGUpLGEucmVtb3ZlRXZlbnRMaXN0ZW5lcihcInNvdXJjZW9wZW5cIixkKSxhLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJ3ZWJraXRzb3VyY2VvcGVuXCIsZCksYi5yZXNvbHZlKGEpfTtyZXR1cm4gYy5kZWJ1Zy5sb2coXCJNZWRpYVNvdXJjZSBzaG91bGQgYmUgY2xvc2VkLiBUaGUgYWN0dWFsIHJlYWR5U3RhdGUgaXM6IFwiK2EucmVhZHlTdGF0ZSksYS5hZGRFdmVudExpc3RlbmVyKFwic291cmNlb3BlblwiLGQsITEpLGEuYWRkRXZlbnRMaXN0ZW5lcihcIndlYmtpdHNvdXJjZW9wZW5cIixkLCExKSxjLm1lZGlhU291cmNlRXh0LmF0dGFjaE1lZGlhU291cmNlKGEsYy52aWRlb01vZGVsKSxjLmRlYnVnLmxvZyhcIk1lZGlhU291cmNlIGF0dGFjaGVkIHRvIHZpZGVvLiAgV2FpdGluZyBvbiBvcGVuLi4uXCIpLGIucHJvbWlzZX0sTz1mdW5jdGlvbigpe3ZhciBjPXRoaXM7dCYmdC5yZXNldChCKSx2JiZ2LnJlc2V0KEIpLGImJmMubWVkaWFTb3VyY2VFeHQuZGV0YWNoTWVkaWFTb3VyY2UoYy52aWRlb01vZGVsKSxBPSExLEM9bnVsbCxEPVtdLHM9bnVsbCx0PW51bGwsdj1udWxsLHg9bnVsbCxxPW51bGwscj1udWxsLGI9bnVsbCxhPW51bGx9LFA9ZnVuY3Rpb24oYixjLGQsZSl7aWYoYiYmYyYmZClpZihudWxsPT09dCYmbnVsbD09PXYmJm51bGw9PT14KXt2YXIgZj1cIk5vIHN0cmVhbXMgdG8gcGxheS5cIjt0aGlzLmVyckhhbmRsZXIubWFuaWZlc3RFcnJvcihmLFwibm9zdHJlYW1zXCIsYSksdGhpcy5kZWJ1Zy5sb2coZiksZS5yZWplY3QoKX1lbHNlIHRoaXMuZGVidWcubG9nKFwiTWVkaWFTb3VyY2UgaW5pdGlhbGl6ZWQhXCIpLGUucmVzb2x2ZSghMCl9LFI9ZnVuY3Rpb24oKXt0aGlzLmRlYnVnLmxvZyhcIkdldHRpbmcgTWVkaWFTb3VyY2UgcmVhZHkuLi5cIik7dmFyIGE9US5kZWZlcigpLGM9ITEsZD0hMSxlPSExLGY9dGhpcyxnPWYubWFuaWZlc3RNb2RlbC5nZXRWYWx1ZSgpLGg9Zi5tYW5pZmVzdEV4dC5nZXRJc0xpdmUoZyk7cmV0dXJuIGYuZGVidWcubG9nKFwiR2F0aGVyaW5nIGluZm9ybWF0aW9uIGZvciBidWZmZXJzLiAoMSlcIiksZi5tYW5pZmVzdEV4dC5nZXREdXJhdGlvbihnLGgpLnRoZW4oZnVuY3Rpb24oKXtmLm1hbmlmZXN0RXh0LmdldFZpZGVvRGF0YShnLEUpLnRoZW4oZnVuY3Rpb24oaCl7cmV0dXJuIG51bGwhPT1oPyhmLmRlYnVnLmxvZyhcIkNyZWF0ZSB2aWRlbyBidWZmZXIuXCIpLGYubWFuaWZlc3RFeHQuZ2V0RGF0YUluZGV4KGgsZyxFKS50aGVuKGZ1bmN0aW9uKGEpe3U9YSxmLmRlYnVnLmxvZyhcIlNhdmUgdmlkZW8gdHJhY2s6IFwiK3UpfSksZi5tYW5pZmVzdEV4dC5nZXRDb2RlYyhoKS50aGVuKGZ1bmN0aW9uKGEpe3JldHVybiBmLmRlYnVnLmxvZyhcIlZpZGVvIGNvZGVjOiBcIithKSxxPWEsZi5tYW5pZmVzdEV4dC5nZXRDb250ZW50UHJvdGVjdGlvbkRhdGEoaCkudGhlbihmdW5jdGlvbihjKXtpZihmLmRlYnVnLmxvZyhcIlZpZGVvIGNvbnRlbnRQcm90ZWN0aW9uXCIpLGMmJiFmLmNhcGFiaWxpdGllcy5zdXBwb3J0c01lZGlhS2V5cygpKXJldHVybiBmLmVyckhhbmRsZXIuY2FwYWJpbGl0eUVycm9yKFwibWVkaWFrZXlzXCIpLFEud2hlbihudWxsKTtpZihzPWMsIWYuY2FwYWJpbGl0aWVzLnN1cHBvcnRzQ29kZWMoZi52aWRlb01vZGVsLmdldEVsZW1lbnQoKSxhKSl7dmFyIGQ9XCJWaWRlbyBDb2RlYyAoXCIrYStcIikgaXMgbm90IHN1cHBvcnRlZC5cIjtyZXR1cm4gZi5lcnJIYW5kbGVyLm1hbmlmZXN0RXJyb3IoZCxcImNvZGVjXCIsZyksZi5kZWJ1Zy5sb2coZCksUS53aGVuKG51bGwpfXJldHVybiBmLnNvdXJjZUJ1ZmZlckV4dC5jcmVhdGVTb3VyY2VCdWZmZXIoYixhKX0pfSkudGhlbihmdW5jdGlvbihnKXtudWxsPT09Zz9mLmRlYnVnLmxvZyhcIk5vIGJ1ZmZlciB3YXMgY3JlYXRlZCwgc2tpcHBpbmcgdmlkZW8gc3RyZWFtLlwiKToodD1mLnN5c3RlbS5nZXRPYmplY3QoXCJidWZmZXJDb250cm9sbGVyXCIpLHQuaW5pdGlhbGl6ZShcInZpZGVvXCIsRSxoLGcsZi52aWRlb01vZGVsLGYucmVxdWVzdFNjaGVkdWxlcixmLmZyYWdtZW50Q29udHJvbGxlcixiKSxmLmRlYnVnLmxvZyhcIlZpZGVvIGlzIHJlYWR5IVwiKSksYz0hMCxQLmNhbGwoZixjLGQsZSxhKX0sZnVuY3Rpb24oKXtmLmVyckhhbmRsZXIubWVkaWFTb3VyY2VFcnJvcihcIkVycm9yIGNyZWF0aW5nIHZpZGVvIHNvdXJjZSBidWZmZXIuXCIpLGM9ITAsUC5jYWxsKGYsYyxkLGUsYSl9KSk6KGYuZGVidWcubG9nKFwiTm8gdmlkZW8gZGF0YS5cIiksYz0hMCxQLmNhbGwoZixjLGQsZSxhKSksZi5tYW5pZmVzdEV4dC5nZXRBdWRpb0RhdGFzKGcsRSl9KS50aGVuKGZ1bmN0aW9uKGgpe3JldHVybiBudWxsIT09aCYmaC5sZW5ndGg+MD8oZi5kZWJ1Zy5sb2coXCJIYXZlIGF1ZGlvIHN0cmVhbXM6IFwiK2gubGVuZ3RoKSxmLm1hbmlmZXN0RXh0LmdldFByaW1hcnlBdWRpb0RhdGEoZyxFKS50aGVuKGZ1bmN0aW9uKGgpe2YubWFuaWZlc3RFeHQuZ2V0RGF0YUluZGV4KGgsZyxFKS50aGVuKGZ1bmN0aW9uKGEpe3c9YSxmLmRlYnVnLmxvZyhcIlNhdmUgYXVkaW8gdHJhY2s6IFwiK3cpfSksZi5tYW5pZmVzdEV4dC5nZXRDb2RlYyhoKS50aGVuKGZ1bmN0aW9uKGEpe3JldHVybiBmLmRlYnVnLmxvZyhcIkF1ZGlvIGNvZGVjOiBcIithKSxyPWEsZi5tYW5pZmVzdEV4dC5nZXRDb250ZW50UHJvdGVjdGlvbkRhdGEoaCkudGhlbihmdW5jdGlvbihjKXtpZihmLmRlYnVnLmxvZyhcIkF1ZGlvIGNvbnRlbnRQcm90ZWN0aW9uXCIpLGMmJiFmLmNhcGFiaWxpdGllcy5zdXBwb3J0c01lZGlhS2V5cygpKXJldHVybiBmLmVyckhhbmRsZXIuY2FwYWJpbGl0eUVycm9yKFwibWVkaWFrZXlzXCIpLFEud2hlbihudWxsKTtpZihzPWMsIWYuY2FwYWJpbGl0aWVzLnN1cHBvcnRzQ29kZWMoZi52aWRlb01vZGVsLmdldEVsZW1lbnQoKSxhKSl7dmFyIGQ9XCJBdWRpbyBDb2RlYyAoXCIrYStcIikgaXMgbm90IHN1cHBvcnRlZC5cIjtyZXR1cm4gZi5lcnJIYW5kbGVyLm1hbmlmZXN0RXJyb3IoZCxcImNvZGVjXCIsZyksZi5kZWJ1Zy5sb2coZCksUS53aGVuKG51bGwpfXJldHVybiBmLnNvdXJjZUJ1ZmZlckV4dC5jcmVhdGVTb3VyY2VCdWZmZXIoYixhKX0pfSkudGhlbihmdW5jdGlvbihnKXtudWxsPT09Zz9mLmRlYnVnLmxvZyhcIk5vIGJ1ZmZlciB3YXMgY3JlYXRlZCwgc2tpcHBpbmcgYXVkaW8gc3RyZWFtLlwiKToodj1mLnN5c3RlbS5nZXRPYmplY3QoXCJidWZmZXJDb250cm9sbGVyXCIpLHYuaW5pdGlhbGl6ZShcImF1ZGlvXCIsRSxoLGcsZi52aWRlb01vZGVsLGYucmVxdWVzdFNjaGVkdWxlcixmLmZyYWdtZW50Q29udHJvbGxlcixiKSxmLmRlYnVnLmxvZyhcIkF1ZGlvIGlzIHJlYWR5IVwiKSksZD0hMCxQLmNhbGwoZixjLGQsZSxhKX0sZnVuY3Rpb24oKXtmLmVyckhhbmRsZXIubWVkaWFTb3VyY2VFcnJvcihcIkVycm9yIGNyZWF0aW5nIGF1ZGlvIHNvdXJjZSBidWZmZXIuXCIpLGQ9ITAsUC5jYWxsKGYsYyxkLGUsYSl9KX0pKTooZi5kZWJ1Zy5sb2coXCJObyBhdWRpbyBzdHJlYW1zLlwiKSxkPSEwLFAuY2FsbChmLGMsZCxlLGEpKSxmLm1hbmlmZXN0RXh0LmdldFRleHREYXRhKGcsRSl9KS50aGVuKGZ1bmN0aW9uKGgpe3ZhciBpO251bGwhPT1oPyhmLm1hbmlmZXN0RXh0LmdldERhdGFJbmRleChoLGcsRSkudGhlbihmdW5jdGlvbihhKXt5PWEsZi5kZWJ1Zy5sb2coXCJTYXZlIHRleHQgdHJhY2s6IFwiK3kpfSksZi5tYW5pZmVzdEV4dC5nZXRNaW1lVHlwZShoKS50aGVuKGZ1bmN0aW9uKGEpe3JldHVybiBpPWEsZi5zb3VyY2VCdWZmZXJFeHQuY3JlYXRlU291cmNlQnVmZmVyKGIsaSl9KS50aGVuKGZ1bmN0aW9uKGIpe251bGw9PT1iP2YuZGVidWcubG9nKFwiU291cmNlIGJ1ZmZlciB3YXMgbm90IGNyZWF0ZWQgZm9yIHRleHQgdHJhY2tcIik6KHg9Zi5zeXN0ZW0uZ2V0T2JqZWN0KFwidGV4dENvbnRyb2xsZXJcIikseC5pbml0aWFsaXplKEUsaCxiLGYudmlkZW9Nb2RlbCksYi5oYXNPd25Qcm9wZXJ0eShcImluaXRpYWxpemVcIikmJmIuaW5pdGlhbGl6ZShpLHgpLGYuZGVidWcubG9nKFwiVGV4dCBpcyByZWFkeSFcIiksZT0hMCxQLmNhbGwoZixjLGQsZSxhKSl9LGZ1bmN0aW9uKGIpe2YuZGVidWcubG9nKFwiRXJyb3IgY3JlYXRpbmcgdGV4dCBzb3VyY2UgYnVmZmVyOlwiKSxmLmRlYnVnLmxvZyhiKSxmLmVyckhhbmRsZXIubWVkaWFTb3VyY2VFcnJvcihcIkVycm9yIGNyZWF0aW5nIHRleHQgc291cmNlIGJ1ZmZlci5cIiksZT0hMCxQLmNhbGwoZixjLGQsZSxhKX0pKTooZi5kZWJ1Zy5sb2coXCJObyB0ZXh0IHRyYWNrcy5cIiksZT0hMCxQLmNhbGwoZixjLGQsZSxhKSl9KX0pLGEucHJvbWlzZX0sUz1mdW5jdGlvbigpe3ZhciBhPXRoaXMsYz1RLmRlZmVyKCksZD1hLm1hbmlmZXN0TW9kZWwuZ2V0VmFsdWUoKSxlPWEubWFuaWZlc3RFeHQuZ2V0SXNMaXZlKGQpO3JldHVybiBhLmRlYnVnLmxvZyhcIkdldHRpbmcgcmVhZHkgZm9yIHBsYXliYWNrLi4uXCIpLGEubWFuaWZlc3RFeHQuZ2V0RHVyYXRpb25Gb3JQZXJpb2QoRSxhLm1hbmlmZXN0TW9kZWwuZ2V0VmFsdWUoKSxlKS50aGVuKGZ1bmN0aW9uKGEpe2w9YX0pLGEubWFuaWZlc3RFeHQuZ2V0RHVyYXRpb24oYS5tYW5pZmVzdE1vZGVsLmdldFZhbHVlKCksZSkudGhlbihmdW5jdGlvbihjKXtyZXR1cm4gYS5kZWJ1Zy5sb2coXCJTZXR0aW5nIGR1cmF0aW9uOiBcIitjKSxhLm1lZGlhU291cmNlRXh0LnNldER1cmF0aW9uKGIsYyl9KS50aGVuKGZ1bmN0aW9uKCl7cmV0dXJuIGEuZGVidWcubG9nKFwiRHVyYXRpb24gc3VjY2Vzc2Z1bGx5IHNldC5cIiksYS5tYW5pZmVzdEV4dC5nZXRQZXJpb2RTdGFydChhLm1hbmlmZXN0TW9kZWwuZ2V0VmFsdWUoKSxFKX0pLnRoZW4oZnVuY3Rpb24oYSl7Rj1hLEE9ITAsYy5yZXNvbHZlKCEwKX0pLGMucHJvbWlzZX0sVD1mdW5jdGlvbigpe3ZhciBhPXRoaXM7YS5kZWJ1Zy5sb2coXCJHb3QgbG9hZG1ldGFkYXRhIGV2ZW50LlwiKSxjLnJlc29sdmUobnVsbCl9LFU9ZnVuY3Rpb24oKXt0aGlzLmRlYnVnLmxvZyhcIkdvdCBwbGF5IGV2ZW50LlwiKSxBJiYobnVsbCE9PUY/KHRoaXMuZGVidWcubG9nKFwiU3RhcnRpbmcgc2VnbWVudCBsb2FkaW5nIGF0IG9mZnNldDogXCIrRiksdCYmdC5zZWVrKEYpLHYmJnYuc2VlayhGKSx4JiZ4LnNlZWsoRikpOih0JiZ0LnN0YXJ0KCksdiYmdi5zdGFydCgpLHgmJnguc3RhcnQoKSkpfSxWPWZ1bmN0aW9uKCl7dGhpcy5kZWJ1Zy5sb2coXCJHb3QgcGF1c2UgZXZlbnQuXCIpLHRoaXMuc2NoZWR1bGVXaGlsZVBhdXNlZHx8YWIuY2FsbCh0aGlzKX0sVz1mdW5jdGlvbihhKXt2YXIgYj1hLnNyY0VsZW1lbnQuZXJyb3IsYz1iLmNvZGUsZD1cIlwiO2lmKC0xIT09Yyl7c3dpdGNoKGMpe2Nhc2UgMTpkPVwiTUVESUFfRVJSX0FCT1JURURcIjticmVhaztjYXNlIDI6ZD1cIk1FRElBX0VSUl9ORVRXT1JLXCI7YnJlYWs7Y2FzZSAzOmQ9XCJNRURJQV9FUlJfREVDT0RFXCI7YnJlYWs7Y2FzZSA0OmQ9XCJNRURJQV9FUlJfU1JDX05PVF9TVVBQT1JURURcIjticmVhaztjYXNlIDU6ZD1cIk1FRElBX0VSUl9FTkNSWVBURURcIn1CPSEwLHRoaXMuZGVidWcubG9nKFwiVmlkZW8gRWxlbWVudCBFcnJvcjogXCIrZCksdGhpcy5kZWJ1Zy5sb2coYiksdGhpcy5lcnJIYW5kbGVyLm1lZGlhU291cmNlRXJyb3IoZCksdGhpcy5yZXNldCgpfX0sWD1mdW5jdGlvbigpe3RoaXMuZGVidWcubG9nKFwiR290IHNlZWtpbmcgZXZlbnQuXCIpO3ZhciBhPXRoaXMudmlkZW9Nb2RlbC5nZXRDdXJyZW50VGltZSgpO3QmJnQuc2VlayhhKSx2JiZ2LnNlZWsoYSl9LFk9ZnVuY3Rpb24oKXt0aGlzLmRlYnVnLmxvZyhcIlNlZWsgY29tcGxldGUuXCIpLHRoaXMudmlkZW9Nb2RlbC5saXN0ZW4oXCJzZWVraW5nXCIsaCksdGhpcy52aWRlb01vZGVsLnVubGlzdGVuKFwic2Vla2VkXCIsaSl9LFo9ZnVuY3Rpb24oKXtfLmNhbGwodGhpcyl9LCQ9ZnVuY3Rpb24oKXtfLmNhbGwodGhpcyl9LF89ZnVuY3Rpb24oKXt0JiZ0LnVwZGF0ZUJ1ZmZlclN0YXRlKCksdiYmdi51cGRhdGVCdWZmZXJTdGF0ZSgpfSxhYj1mdW5jdGlvbigpe3QmJnQuc3RvcCgpLHYmJnYuc3RvcCgpfSxiYj1mdW5jdGlvbihkKXt2YXIgZT10aGlzO3JldHVybiBlLmRlYnVnLmxvZyhcIlN0cmVhbSBzdGFydCBsb2FkaW5nLlwiKSxhPWQsZS5tZWRpYVNvdXJjZUV4dC5jcmVhdGVNZWRpYVNvdXJjZSgpLnRoZW4oZnVuY3Rpb24oYSl7cmV0dXJuIGUuZGVidWcubG9nKFwiTWVkaWFTb3VyY2UgY3JlYXRlZC5cIiksTi5jYWxsKGUsYSl9KS50aGVuKGZ1bmN0aW9uKGEpe3JldHVybiBiPWEsZS5kZWJ1Zy5sb2coXCJNZWRpYVNvdXJjZSBzZXQgdXAuXCIpLFIuY2FsbChlKX0pLnRoZW4oZnVuY3Rpb24oKXtyZXR1cm4gZS5kZWJ1Zy5sb2coXCJTdGFydCBpbml0aWFsaXppbmcgcGxheWJhY2suXCIpLFMuY2FsbChlKX0pLnRoZW4oZnVuY3Rpb24oKXtyZXR1cm4gej8oZS5kZWJ1Zy5sb2coXCJQbGF5YmFjayBpbml0aWFsaXplZCFcIiksYy5wcm9taXNlKTp2b2lkIDB9KS50aGVuKGZ1bmN0aW9uKCl7ZS5kZWJ1Zy5sb2coXCJlbGVtZW50IGxvYWRlZCFcIiksMD09PUUmJkcuY2FsbChlKX0pfSxjYj1mdW5jdGlvbigpe3RoaXMuZGVidWcubG9nKFwiQ3VycmVudCB0aW1lIGhhcyBjaGFuZ2VkLCBibG9jayBwcm9ncmFtbWF0aWMgc2Vlay5cIiksdGhpcy52aWRlb01vZGVsLnVubGlzdGVuKFwic2Vla2luZ1wiLGgpLHRoaXMudmlkZW9Nb2RlbC5saXN0ZW4oXCJzZWVrZWRcIixpKX0sZGI9ZnVuY3Rpb24oKXt0JiYhdC5pc0J1ZmZlcmluZ0NvbXBsZXRlZCgpfHx2JiYhdi5pc0J1ZmZlcmluZ0NvbXBsZXRlZCgpfHxiJiZ0aGlzLm1lZGlhU291cmNlRXh0LnNpZ25hbEVuZE9mU3RyZWFtKGIpfSxlYj1mdW5jdGlvbigpe2FiLmNhbGwodGhpcyl9LGZiPWZ1bmN0aW9uKCl7dmFyIGEsYixjPXRoaXMsZD1jLm1hbmlmZXN0TW9kZWwuZ2V0VmFsdWUoKTtjLmRlYnVnLmxvZyhcIk1hbmlmZXN0IHVwZGF0ZWQuLi4gc2V0IG5ldyBkYXRhIG9uIGJ1ZmZlcnMuXCIpLHQmJihhPXQuZ2V0RGF0YSgpLGEmJmEuaGFzT3duUHJvcGVydHkoXCJpZFwiKT9jLm1hbmlmZXN0RXh0LmdldERhdGFGb3JJZChhLmlkLGQsRSkudGhlbihmdW5jdGlvbihhKXt0LnNldERhdGEoYSl9KTpjLm1hbmlmZXN0RXh0LmdldERhdGFGb3JJbmRleCh1LGQsRSkudGhlbihmdW5jdGlvbihhKXt0LnNldERhdGEoYSl9KSksdiYmKGI9di5nZXREYXRhKCksYiYmYi5oYXNPd25Qcm9wZXJ0eShcImlkXCIpP2MubWFuaWZlc3RFeHQuZ2V0RGF0YUZvcklkKGIuaWQsZCxFKS50aGVuKGZ1bmN0aW9uKGEpe3Yuc2V0RGF0YShhKX0pOmMubWFuaWZlc3RFeHQuZ2V0RGF0YUZvckluZGV4KHcsZCxFKS50aGVuKGZ1bmN0aW9uKGEpe3Yuc2V0RGF0YShhKX0pKX07cmV0dXJue3N5c3RlbTp2b2lkIDAsdmlkZW9Nb2RlbDp2b2lkIDAsbWFuaWZlc3RMb2FkZXI6dm9pZCAwLG1hbmlmZXN0TW9kZWw6dm9pZCAwLG1lZGlhU291cmNlRXh0OnZvaWQgMCxzb3VyY2VCdWZmZXJFeHQ6dm9pZCAwLGJ1ZmZlckV4dDp2b2lkIDAsbWFuaWZlc3RFeHQ6dm9pZCAwLGZyYWdtZW50Q29udHJvbGxlcjp2b2lkIDAsYWJyQ29udHJvbGxlcjp2b2lkIDAsZnJhZ21lbnRFeHQ6dm9pZCAwLHByb3RlY3Rpb25Nb2RlbDp2b2lkIDAscHJvdGVjdGlvbkNvbnRyb2xsZXI6dm9pZCAwLHByb3RlY3Rpb25FeHQ6dm9pZCAwLGNhcGFiaWxpdGllczp2b2lkIDAsZGVidWc6dm9pZCAwLG1ldHJpY3NFeHQ6dm9pZCAwLGVyckhhbmRsZXI6dm9pZCAwLHJlcXVlc3RTY2hlZHVsZXI6dm9pZCAwLHNjaGVkdWxlV2hpbGVQYXVzZWQ6dm9pZCAwLHNldHVwOmZ1bmN0aW9uKCl7dGhpcy5zeXN0ZW0ubWFwSGFuZGxlcihcIm1hbmlmZXN0VXBkYXRlZFwiLHZvaWQgMCxmYi5iaW5kKHRoaXMpKSx0aGlzLnN5c3RlbS5tYXBIYW5kbGVyKFwic2V0Q3VycmVudFRpbWVcIix2b2lkIDAsY2IuYmluZCh0aGlzKSksdGhpcy5zeXN0ZW0ubWFwSGFuZGxlcihcImJ1ZmZlcmluZ0NvbXBsZXRlZFwiLHZvaWQgMCxkYi5iaW5kKHRoaXMpKSx0aGlzLnN5c3RlbS5tYXBIYW5kbGVyKFwic2VnbWVudExvYWRpbmdGYWlsZWRcIix2b2lkIDAsZWIuYmluZCh0aGlzKSksYz1RLmRlZmVyKCksZT1VLmJpbmQodGhpcyksZj1WLmJpbmQodGhpcyksZz1XLmJpbmQodGhpcyksaD1YLmJpbmQodGhpcyksaT1ZLmJpbmQodGhpcyksaz1aLmJpbmQodGhpcyksaj0kLmJpbmQodGhpcyksZD1ULmJpbmQodGhpcyl9LGxvYWQ6ZnVuY3Rpb24oYSxiKXtFPWIsYmIuY2FsbCh0aGlzLGEpfSxzZXRWaWRlb01vZGVsOmZ1bmN0aW9uKGEpe3RoaXMudmlkZW9Nb2RlbD1hLHRoaXMudmlkZW9Nb2RlbC5saXN0ZW4oXCJwbGF5XCIsZSksdGhpcy52aWRlb01vZGVsLmxpc3RlbihcInBhdXNlXCIsZiksdGhpcy52aWRlb01vZGVsLmxpc3RlbihcImVycm9yXCIsZyksdGhpcy52aWRlb01vZGVsLmxpc3RlbihcInNlZWtpbmdcIixoKSx0aGlzLnZpZGVvTW9kZWwubGlzdGVuKFwidGltZXVwZGF0ZVwiLGopLHRoaXMudmlkZW9Nb2RlbC5saXN0ZW4oXCJwcm9ncmVzc1wiLGspLHRoaXMudmlkZW9Nb2RlbC5saXN0ZW4oXCJsb2FkZWRtZXRhZGF0YVwiLGQpfSxpbml0UHJvdGVjdGlvbjpmdW5jdGlvbigpe209Si5iaW5kKHRoaXMpLG49Sy5iaW5kKHRoaXMpLG89TC5iaW5kKHRoaXMpLHA9TS5iaW5kKHRoaXMpLHRoaXMucHJvdGVjdGlvbk1vZGVsPXRoaXMuc3lzdGVtLmdldE9iamVjdChcInByb3RlY3Rpb25Nb2RlbFwiKSx0aGlzLnByb3RlY3Rpb25Nb2RlbC5pbml0KHRoaXMuZ2V0VmlkZW9Nb2RlbCgpKSx0aGlzLnByb3RlY3Rpb25Db250cm9sbGVyPXRoaXMuc3lzdGVtLmdldE9iamVjdChcInByb3RlY3Rpb25Db250cm9sbGVyXCIpLHRoaXMucHJvdGVjdGlvbkNvbnRyb2xsZXIuaW5pdCh0aGlzLnZpZGVvTW9kZWwsdGhpcy5wcm90ZWN0aW9uTW9kZWwpLHRoaXMucHJvdGVjdGlvbk1vZGVsLmxpc3RlblRvTmVlZEtleShtKSx0aGlzLnByb3RlY3Rpb25Nb2RlbC5saXN0ZW5Ub0tleU1lc3NhZ2UobiksdGhpcy5wcm90ZWN0aW9uTW9kZWwubGlzdGVuVG9LZXlFcnJvcihwKSx0aGlzLnByb3RlY3Rpb25Nb2RlbC5saXN0ZW5Ub0tleUFkZGVkKG8pfSxnZXRWaWRlb01vZGVsOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMudmlkZW9Nb2RlbH0sZ2V0TWFuaWZlc3RFeHQ6ZnVuY3Rpb24oKXt2YXIgYT10aGlzO3JldHVybiBhLm1hbmlmZXN0RXh0fSxzZXRBdXRvUGxheTpmdW5jdGlvbihhKXt6PWF9LGdldEF1dG9QbGF5OmZ1bmN0aW9uKCl7cmV0dXJuIHp9LHJlc2V0OmZ1bmN0aW9uKCl7SC5jYWxsKHRoaXMpLHRoaXMudmlkZW9Nb2RlbC51bmxpc3RlbihcInBsYXlcIixlKSx0aGlzLnZpZGVvTW9kZWwudW5saXN0ZW4oXCJwYXVzZVwiLGYpLHRoaXMudmlkZW9Nb2RlbC51bmxpc3RlbihcImVycm9yXCIsZyksdGhpcy52aWRlb01vZGVsLnVubGlzdGVuKFwic2Vla2luZ1wiLGgpLHRoaXMudmlkZW9Nb2RlbC51bmxpc3RlbihcInRpbWV1cGRhdGVcIixqKSx0aGlzLnZpZGVvTW9kZWwudW5saXN0ZW4oXCJwcm9ncmVzc1wiLGspLHRoaXMudmlkZW9Nb2RlbC51bmxpc3RlbihcImxvYWRlZG1ldGFkYXRhXCIsZCksTy5jYWxsKHRoaXMpLHRoaXMucHJvdGVjdGlvbkNvbnRyb2xsZXImJnRoaXMucHJvdGVjdGlvbkNvbnRyb2xsZXIudGVhcmRvd25LZXlTeXN0ZW0oQyksdGhpcy5wcm90ZWN0aW9uQ29udHJvbGxlcj12b2lkIDAsdGhpcy5wcm90ZWN0aW9uTW9kZWw9dm9pZCAwLHRoaXMuZnJhZ21lbnRDb250cm9sbGVyPXZvaWQgMCx0aGlzLnJlcXVlc3RTY2hlZHVsZXI9dm9pZCAwLGM9US5kZWZlcigpfSxnZXREdXJhdGlvbjpmdW5jdGlvbigpe3JldHVybiBsfSxzZXRQZXJpb2RJbmRleDpmdW5jdGlvbihhKXtFPWF9LGdldFBlcmlvZEluZGV4OmZ1bmN0aW9uKCl7cmV0dXJuIEV9LGdldFN0YXJ0VGltZTpmdW5jdGlvbigpe3JldHVybiBGfSxwbGF5Okcsc2VlazpJLHBhdXNlOkh9fSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuU3RyZWFtLnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlN0cmVhbX0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlN0cmVhbUNvbnRyb2xsZXI9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt2YXIgYSxiPVtdLGM9NCxkPTMsZT0hMCxmPW51bGwsZz1mdW5jdGlvbigpe2EucGxheSgpfSxoPWZ1bmN0aW9uKCl7YS5wYXVzZSgpfSxpPWZ1bmN0aW9uKGIpe2Euc2VlayhiKX0saj1mdW5jdGlvbihhLGIpe3ZhciBjPWEuZ2V0RWxlbWVudCgpLGQ9Yi5nZXRFbGVtZW50KCk7cmV0dXJuIGQucGFyZW50Tm9kZXx8Yy5wYXJlbnROb2RlLmluc2VydEJlZm9yZShkLGMpLGMuc3R5bGUud2lkdGg9XCIwcHhcIixkLnN0eWxlLndpZHRoPVwiMTAwJVwiLG0oYyxkKSxsKGEpLGsoYiksUS53aGVuKCEwKX0saz1mdW5jdGlvbihhKXthLmxpc3RlbihcInNlZWtpbmdcIixwKSxhLmxpc3RlbihcInByb2dyZXNzXCIsbikscigpJiZhLmxpc3RlbihcInRpbWV1cGRhdGVcIixvKX0sbD1mdW5jdGlvbihhKXthLnVubGlzdGVuKFwic2Vla2luZ1wiLHApLGEudW5saXN0ZW4oXCJwcm9ncmVzc1wiLG4pLGEudW5saXN0ZW4oXCJ0aW1ldXBkYXRlXCIsbyl9LG09ZnVuY3Rpb24oYSxiKXtbXCJjb250cm9sc1wiLFwibG9vcFwiLFwibXV0ZWRcIixcInBsYXliYWNrUmF0ZVwiLFwidm9sdW1lXCJdLmZvckVhY2goZnVuY3Rpb24oYyl7YltjXT1hW2NdfSl9LG49ZnVuY3Rpb24oKXt2YXIgYj1hLmdldFZpZGVvTW9kZWwoKS5nZXRFbGVtZW50KCkuYnVmZmVyZWQ7aWYoYi5sZW5ndGgpe3ZhciBkPWIubGVuZ3RoLTEsZT1iLmVuZChkKSxmPWEuZ2V0U3RhcnRUaW1lKCkrYS5nZXREdXJhdGlvbigpLWU7Yz5mJiYoYS5nZXRWaWRlb01vZGVsKCkudW5saXN0ZW4oXCJwcm9ncmVzc1wiLG4pLHEoKSl9fSxvPWZ1bmN0aW9uKCl7aWYoIWEuZ2V0VmlkZW9Nb2RlbCgpLmdldEVsZW1lbnQoKS5zZWVraW5nKXt2YXIgYj1hLmdldFN0YXJ0VGltZSgpK2EuZ2V0RHVyYXRpb24oKSxjPWEuZ2V0VmlkZW9Nb2RlbCgpLmdldEN1cnJlbnRUaW1lKCk7ZD5iLWMmJnYoYSxyKCkpfX0scD1mdW5jdGlvbigpe3ZhciBiPWEuZ2V0VmlkZW9Nb2RlbCgpLmdldEN1cnJlbnRUaW1lKCksYz1zKGIpO2MmJmMhPT1hJiZ2KGEsYyxiKX0scT1mdW5jdGlvbigpe3ZhciBhPXIoKTthJiZhLnNlZWsoYS5nZXRTdGFydFRpbWUoKSl9LHI9ZnVuY3Rpb24oKXt2YXIgYz1hLmdldFBlcmlvZEluZGV4KCkrMTtyZXR1cm4gYzxiLmxlbmd0aD9iW2NdOm51bGx9LHM9ZnVuY3Rpb24oYSl7Zm9yKHZhciBjPTAsZD1udWxsLGU9MCxmPWIubGVuZ3RoO2Y+ZTtlKyspaWYoZD1iW2VdLGMrPWQuZ2V0RHVyYXRpb24oKSxjPmEpcmV0dXJuIGR9LHQ9ZnVuY3Rpb24oKXt2YXIgYT10aGlzLnN5c3RlbS5nZXRPYmplY3QoXCJ2aWRlb01vZGVsXCIpLGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInZpZGVvXCIpO3JldHVybiBhLnNldEVsZW1lbnQoYiksYX0sdT1mdW5jdGlvbihhKXthLnBhcmVudE5vZGUmJmEucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChhKX0sdj1mdW5jdGlvbihiLGMsZCl7YiYmYyYmYiE9PWMmJlEud2hlbihmfHwhMCkudGhlbihmdW5jdGlvbigpe2IucGF1c2UoKSxhPWMsZj1qKGIuZ2V0VmlkZW9Nb2RlbCgpLGMuZ2V0VmlkZW9Nb2RlbCgpKSxkP2koYi5nZXRWaWRlb01vZGVsKCkuZ2V0Q3VycmVudFRpbWUoKSk6aShjLmdldFN0YXJ0VGltZSgpKSxnKCl9KX07cmV0dXJue3N5c3RlbTp2b2lkIDAsdmlkZW9Nb2RlbDp2b2lkIDAsbWFuaWZlc3RMb2FkZXI6dm9pZCAwLG1hbmlmZXN0VXBkYXRlcjp2b2lkIDAsbWFuaWZlc3RNb2RlbDp2b2lkIDAsbWVkaWFTb3VyY2VFeHQ6dm9pZCAwLHNvdXJjZUJ1ZmZlckV4dDp2b2lkIDAsYnVmZmVyRXh0OnZvaWQgMCxtYW5pZmVzdEV4dDp2b2lkIDAsZnJhZ21lbnRDb250cm9sbGVyOnZvaWQgMCxhYnJDb250cm9sbGVyOnZvaWQgMCxmcmFnbWVudEV4dDp2b2lkIDAsY2FwYWJpbGl0aWVzOnZvaWQgMCxkZWJ1Zzp2b2lkIDAsbWV0cmljc0V4dDp2b2lkIDAsZXJySGFuZGxlcjp2b2lkIDAsZ2V0TWFuaWZlc3RFeHQ6ZnVuY3Rpb24oKXtyZXR1cm4gYS5nZXRNYW5pZmVzdEV4dCgpfSxzZXRBdXRvUGxheTpmdW5jdGlvbihhKXtlPWF9LGdldEF1dG9QbGF5OmZ1bmN0aW9uKCl7cmV0dXJuIGV9LGdldFZpZGVvTW9kZWw6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy52aWRlb01vZGVsfSxzZXRWaWRlb01vZGVsOmZ1bmN0aW9uKGEpe3RoaXMudmlkZW9Nb2RlbD1hfSxsb2FkOmZ1bmN0aW9uKGMpe3ZhciBkLGY9dGhpcztmLm1hbmlmZXN0TG9hZGVyLmxvYWQoYykudGhlbihmdW5jdGlvbihjKXtmLm1hbmlmZXN0TW9kZWwuc2V0VmFsdWUoYyksZi5kZWJ1Zy5sb2coXCJNYW5pZmVzdCBoYXMgbG9hZGVkLlwiKSxmLmRlYnVnLmxvZyhmLm1hbmlmZXN0TW9kZWwuZ2V0VmFsdWUoKSksZi5tYW5pZmVzdFVwZGF0ZXIuaW5pdCgpLGYubWFuaWZlc3RFeHQuZ2V0UGVyaW9kQ291bnQoYykudGhlbihmdW5jdGlvbihnKXtmb3IodmFyIGg9MDtnPmg7aCsrKWQ9Zi5zeXN0ZW0uZ2V0T2JqZWN0KFwic3RyZWFtXCIpLGQuc2V0VmlkZW9Nb2RlbCgwPT09aD9mLnZpZGVvTW9kZWw6dC5jYWxsKGYpKSxkLmluaXRQcm90ZWN0aW9uKCksZC5zZXRBdXRvUGxheShlKSxkLmxvYWQoYyxoKSxiLnB1c2goZCk7YT1iWzBdLGsoYS5nZXRWaWRlb01vZGVsKCkpfSl9LGZ1bmN0aW9uKCl7Zi5yZXNldCgpfSl9LHJlc2V0OmZ1bmN0aW9uKCl7YSYmbChhLmdldFZpZGVvTW9kZWwoKSk7Zm9yKHZhciBjPTAsZD1iLmxlbmd0aDtkPmM7YysrKXt2YXIgZT1iW2NdO2UucmVzZXQoKSxlIT09YSYmdShlLmdldFZpZGVvTW9kZWwoKS5nZXRFbGVtZW50KCkpfWI9W10sdGhpcy5tYW5pZmVzdFVwZGF0ZXIuc3RvcCgpLHRoaXMubWFuaWZlc3RNb2RlbC5zZXRWYWx1ZShudWxsKSxmPW51bGwsYT1udWxsfSxwbGF5Omcsc2VlazppLHBhdXNlOmh9fSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuU3RyZWFtQ29udHJvbGxlci5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOk1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5TdHJlYW1Db250cm9sbGVyfSxNZWRpYVBsYXllci5tb2RlbHMuVmlkZW9Nb2RlbD1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3ZhciBhLGI9W10sYz1mdW5jdGlvbigpe3JldHVybiBiLmxlbmd0aD4wfSxkPWZ1bmN0aW9uKGMpe251bGwhPT1jJiZiW2NdIT09ITAmJihiLnB1c2goYyksYltjXT0hMCxhLnBsYXliYWNrUmF0ZT0wKX0sZT1mdW5jdGlvbihkKXtpZihudWxsIT09ZCl7YltkXT0hMTt2YXIgZT1iLmluZGV4T2YoZCk7LTEhPT1lJiZiLnNwbGljZShlLDEpLGMoKT09PSExJiYoYS5wbGF5YmFja1JhdGU9MSl9fSxmPWZ1bmN0aW9uKGEsYil7Yj9kKGEpOmUoYSl9O3JldHVybntzeXN0ZW06dm9pZCAwLHNldHVwOmZ1bmN0aW9uKCl7fSxwbGF5OmZ1bmN0aW9uKCl7YS5wbGF5KCl9LHBhdXNlOmZ1bmN0aW9uKCl7YS5wYXVzZSgpfSxpc1BhdXNlZDpmdW5jdGlvbigpe3JldHVybiBhLnBhdXNlZH0sZ2V0UGxheWJhY2tSYXRlOmZ1bmN0aW9uKCl7cmV0dXJuIGEucGxheWJhY2tSYXRlfSxzZXRQbGF5YmFja1JhdGU6ZnVuY3Rpb24oYil7YS5wbGF5YmFja1JhdGU9Yn0sZ2V0Q3VycmVudFRpbWU6ZnVuY3Rpb24oKXtyZXR1cm4gYS5jdXJyZW50VGltZX0sc2V0Q3VycmVudFRpbWU6ZnVuY3Rpb24oYil7YS5jdXJyZW50VGltZSE9YiYmKGEuY3VycmVudFRpbWU9Yil9LGxpc3RlbjpmdW5jdGlvbihiLGMpe2EuYWRkRXZlbnRMaXN0ZW5lcihiLGMsITEpfSx1bmxpc3RlbjpmdW5jdGlvbihiLGMpe2EucmVtb3ZlRXZlbnRMaXN0ZW5lcihiLGMsITEpfSxnZXRFbGVtZW50OmZ1bmN0aW9uKCl7cmV0dXJuIGF9LHNldEVsZW1lbnQ6ZnVuY3Rpb24oYil7YT1ifSxzZXRTb3VyY2U6ZnVuY3Rpb24oYil7YS5zcmM9Yn0sc3RhbGxTdHJlYW06Zixpc1N0YWxsZWQ6Y319LE1lZGlhUGxheWVyLm1vZGVscy5WaWRlb01vZGVsLnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIubW9kZWxzLlZpZGVvTW9kZWx9LE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5WaWRlb01vZGVsRXh0ZW5zaW9ucz1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3JldHVybntnZXREcm9wcGVkRnJhbWVzOmZ1bmN0aW9uKGEpe3ZhciBiPW51bGwhPT1hLndlYmtpdERyb3BwZWRGcmFtZUNvdW50LGM9LTE7cmV0dXJuIGImJihjPWEud2Via2l0RHJvcHBlZEZyYW1lQ291bnQpLGN9fX0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlZpZGVvTW9kZWxFeHRlbnNpb25zLnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlZpZGVvTW9kZWxFeHRlbnNpb25zfSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuVGV4dENvbnRyb2xsZXI9ZnVuY3Rpb24oKXt2YXIgYSxiLGM9XCJMT0FESU5HXCIsZD1cIlJFQURZXCIsZT0hMSxmPS0xLGc9ZCxoPWZ1bmN0aW9uKGEpe3RoaXMuZGVidWcubG9nKFwiVGV4dENvbnRyb2xsZXIgc2V0U3RhdGUgdG86XCIrYSksZz1hfSxpPWZ1bmN0aW9uKCl7aWYoZSYmZz09PWQpe3ZhciBiPXRoaXM7aC5jYWxsKGIsYyksYi5pbmRleEhhbmRsZXIuZ2V0SW5pdFJlcXVlc3QoMCxhKS50aGVuKGZ1bmN0aW9uKGEpe2IuZGVidWcubG9nKFwiTG9hZGluZyB0ZXh0IHRyYWNrIGluaXRpYWxpemF0aW9uOiBcIithLnVybCksYi5kZWJ1Zy5sb2coYSksYi5mcmFnbWVudExvYWRlci5sb2FkKGEpLnRoZW4oay5iaW5kKGIsYSksbC5iaW5kKGIsYSkpLGguY2FsbChiLGMpfSl9fSxqPWZ1bmN0aW9uKCl7aS5jYWxsKHRoaXMpfSxrPWZ1bmN0aW9uKGEsYyl7dmFyIGQ9dGhpcztkLmRlYnVnLmxvZyhcIiBUZXh0IHRyYWNrIEJ5dGVzIGZpbmlzaGVkIGxvYWRpbmc6IFwiK2EudXJsKSxkLmZyYWdtZW50Q29udHJvbGxlci5wcm9jZXNzKGMuZGF0YSkudGhlbihmdW5jdGlvbihhKXtudWxsIT09YSYmKGQuZGVidWcubG9nKFwiUHVzaCB0ZXh0IHRyYWNrIGJ5dGVzOiBcIithLmJ5dGVMZW5ndGgpLGQuc291cmNlQnVmZmVyRXh0LmFwcGVuZChiLGEsZC52aWRlb01vZGVsKSl9KX0sbD1mdW5jdGlvbigpe307cmV0dXJue3ZpZGVvTW9kZWw6dm9pZCAwLGZyYWdtZW50TG9hZGVyOnZvaWQgMCxmcmFnbWVudENvbnRyb2xsZXI6dm9pZCAwLGluZGV4SGFuZGxlcjp2b2lkIDAsc291cmNlQnVmZmVyRXh0OnZvaWQgMCxkZWJ1Zzp2b2lkIDAsaW5pdGlhbGl6ZTpmdW5jdGlvbihhLGIsYyxkKXt2YXIgZj10aGlzO2Yuc2V0VmlkZW9Nb2RlbChkKSxmLnNldFBlcmlvZEluZGV4KGEpLGYuc2V0RGF0YShiKSxmLnNldEJ1ZmZlcihjKSxlPSEwfSxnZXRQZXJpb2RJbmRleDpmdW5jdGlvbigpe3JldHVybiBmfSxzZXRQZXJpb2RJbmRleDpmdW5jdGlvbihhKXtmPWF9LGdldFZpZGVvTW9kZWw6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy52aWRlb01vZGVsfSxzZXRWaWRlb01vZGVsOmZ1bmN0aW9uKGEpe3RoaXMudmlkZW9Nb2RlbD1hfSxnZXREYXRhOmZ1bmN0aW9uKCl7cmV0dXJuIGF9LHNldERhdGE6ZnVuY3Rpb24oYil7YT1ifSxnZXRCdWZmZXI6ZnVuY3Rpb24oKXtyZXR1cm4gYn0sc2V0QnVmZmVyOmZ1bmN0aW9uKGEpe2I9YX0scmVzZXQ6ZnVuY3Rpb24oYSxjKXthfHwodGhpcy5zb3VyY2VCdWZmZXJFeHQuYWJvcnQoYyxiKSx0aGlzLnNvdXJjZUJ1ZmZlckV4dC5yZW1vdmVTb3VyY2VCdWZmZXIoYyxiKSl9LHN0YXJ0Omp9fSxNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuVGV4dENvbnRyb2xsZXIucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuVGV4dENvbnRyb2xsZXJ9LE1lZGlhUGxheWVyLnV0aWxzLlRleHRUcmFja0V4dGVuc2lvbnM9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjtyZXR1cm57YWRkVGV4dFRyYWNrOmZ1bmN0aW9uKGEsYixjLGQsZSl7dmFyIGY9YS5hZGRUZXh0VHJhY2soXCJjYXB0aW9uc1wiLGMsZCk7Zi5kZWZhdWx0PWUsZi5tb2RlPVwic2hvd2luZ1wiO2Zvcih2YXIgZyBpbiBiKXt2YXIgaD1iW2ddO2YuYWRkQ3VlKG5ldyBUZXh0VHJhY2tDdWUoaC5zdGFydCxoLmVuZCxoLmRhdGEpKX1yZXR1cm4gUS53aGVuKGYpfSxkZWxldGVDdWVzOmZ1bmN0aW9uKGEpe2Zvcih2YXIgYj1hLnRleHRUcmFja3NbMF0sYz1iLmN1ZXMsZD1jLmxlbmd0aDtkPj0wO2QtLSliLnJlbW92ZUN1ZShjW2RdKTtiLm1vZGU9XCJkaXNhYmxlZFwifX19LE1lZGlhUGxheWVyLmRlcGVuZGVuY2llcy5UZXh0VlRUU291cmNlQnVmZmVyPWZ1bmN0aW9uKCl7dmFyIGEsYixjO3JldHVybntzeXN0ZW06dm9pZCAwLGV2ZW50QnVzOnZvaWQgMCxpbml0aWFsaXplOmZ1bmN0aW9uKGQsZSl7Yz1kLGE9ZS5nZXRWaWRlb01vZGVsKCkuZ2V0RWxlbWVudCgpLGI9ZS5nZXREYXRhKCl9LGFwcGVuZDpmdW5jdGlvbihjKXt2YXIgZD10aGlzO2QuZ2V0UGFyc2VyKCkucGFyc2UoU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShudWxsLG5ldyBVaW50MTZBcnJheShjKSkpLnRoZW4oZnVuY3Rpb24oYyl7dmFyIGU9Yi5SZXByZXNlbnRhdGlvbl9hc0FycmF5WzBdLmlkLGY9Yi5sYW5nO2QuZ2V0VGV4dFRyYWNrRXh0ZW5zaW9ucygpLmFkZFRleHRUcmFjayhhLGMsZSxmLCEwKS50aGVuKGZ1bmN0aW9uKCl7ZC5ldmVudEJ1cy5kaXNwYXRjaEV2ZW50KHt0eXBlOlwidXBkYXRlZW5kXCJ9KX0pfSl9LGFib3J0OmZ1bmN0aW9uKCl7dGhpcy5nZXRUZXh0VHJhY2tFeHRlbnNpb25zKCkuZGVsZXRlQ3VlcyhhKX0sZ2V0UGFyc2VyOmZ1bmN0aW9uKCl7dmFyIGE7cmV0dXJuXCJ0ZXh0L3Z0dFwiPT09YyYmKGE9dGhpcy5zeXN0ZW0uZ2V0T2JqZWN0KFwidnR0UGFyc2VyXCIpKSxhfSxnZXRUZXh0VHJhY2tFeHRlbnNpb25zOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuc3lzdGVtLmdldE9iamVjdChcInRleHRUcmFja0V4dGVuc2lvbnNcIil9LGFkZEV2ZW50TGlzdGVuZXI6ZnVuY3Rpb24oYSxiLGMpe3RoaXMuZXZlbnRCdXMuYWRkRXZlbnRMaXN0ZW5lcihhLGIsYyl9LHJlbW92ZUV2ZW50TGlzdGVuZXI6ZnVuY3Rpb24oYSxiLGMpe3RoaXMuZXZlbnRCdXMucmVtb3ZlRXZlbnRMaXN0ZW5lcihhLGIsYyl9fX0sTWVkaWFQbGF5ZXIuZGVwZW5kZW5jaWVzLlRleHRWVFRTb3VyY2VCdWZmZXIucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci5kZXBlbmRlbmNpZXMuVGV4dFZUVFNvdXJjZUJ1ZmZlcn0sTWVkaWFQbGF5ZXIudXRpbHMuVlRUUGFyc2VyPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGE9ZnVuY3Rpb24oYSl7dmFyIGI9YS5zcGxpdChcIjpcIiksYz1iLmxlbmd0aC0xO3JldHVybiBhPTYwKnBhcnNlSW50KGJbYy0xXSwxMCkrcGFyc2VGbG9hdChiW2NdLDEwKSwyPT09YyYmKGErPTM2MDAqcGFyc2VJbnQoYlswXSwxMCkpLGF9O3JldHVybntwYXJzZTpmdW5jdGlvbihiKXt2YXIgYyxkPS8oPzpcXHJcXG58XFxyfFxcbikvZ20sZT0vLS0+LyxmPS8oXltcXHNdK3xbXFxzXSskKS9nLGc9W107Yj1iLnNwbGl0KGQpLGM9Yi5sZW5ndGg7Zm9yKHZhciBoPTA7Yz5oO2grKyl7dmFyIGk9YltoXTtpZihpLmxlbmd0aD4wJiZcIldFQlZUVFwiIT09aSYmaS5tYXRjaChlKSl7dmFyIGo9aS5zcGxpdChlKSxrPWJbaCsxXTtnLnB1c2goe3N0YXJ0OmEoalswXS5yZXBsYWNlKGYsXCJcIikpLGVuZDphKGpbMV0ucmVwbGFjZShmLFwiXCIpKSxkYXRhOmt9KX19cmV0dXJuIFEud2hlbihnKX19fSxNZWRpYVBsYXllci5ydWxlcy5CYXNlUnVsZXNDb2xsZWN0aW9uPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGE9W107cmV0dXJue2Rvd25sb2FkUmF0aW9SdWxlOnZvaWQgMCxpbnN1ZmZpY2llbnRCdWZmZXJSdWxlOnZvaWQgMCxnZXRSdWxlczpmdW5jdGlvbigpe3JldHVybiBRLndoZW4oYSl9LHNldHVwOmZ1bmN0aW9uKCl7dmFyIGE9dGhpczthLmdldFJ1bGVzKCkudGhlbihmdW5jdGlvbihiKXtiLnB1c2goYS5kb3dubG9hZFJhdGlvUnVsZSksYi5wdXNoKGEuaW5zdWZmaWNpZW50QnVmZmVyUnVsZSl9KX19fSxNZWRpYVBsYXllci5ydWxlcy5CYXNlUnVsZXNDb2xsZWN0aW9uLnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIucnVsZXMuQmFzZVJ1bGVzQ29sbGVjdGlvbn0sTWVkaWFQbGF5ZXIucnVsZXMuRG93bmxvYWRSYXRpb1J1bGU9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt2YXIgYT1mdW5jdGlvbihhLGIsYyl7dmFyIGQ9dGhpcyxlPVEuZGVmZXIoKTtyZXR1cm4gZC5tYW5pZmVzdEV4dC5nZXRSZXByZXNlbnRhdGlvbkZvcihhLGMpLnRoZW4oZnVuY3Rpb24oYSl7ZC5tYW5pZmVzdEV4dC5nZXRCYW5kd2lkdGgoYSkudGhlbihmdW5jdGlvbihhKXtlLnJlc29sdmUoYS9iKX0pfSksZS5wcm9taXNlfTtyZXR1cm57ZGVidWc6dm9pZCAwLG1hbmlmZXN0RXh0OnZvaWQgMCxjaGVja0luZGV4OmZ1bmN0aW9uKGIsYyxkKXt2YXIgZSxmLGcsaCxpLGosayxsLG0sbixvPXRoaXMscD1jLkh0dHBMaXN0LHE9Ljc1O3JldHVybiBvLmRlYnVnLmxvZyhcIkNoZWNraW5nIGRvd25sb2FkIHJhdGlvIHJ1bGUuLi5cIiksYz9udWxsPT09cHx8dm9pZCAwPT09cHx8MD09PXAubGVuZ3RoPyhvLmRlYnVnLmxvZyhcIk5vIHJlcXVlc3RzIG1hZGUgZm9yIHRoaXMgc3RyZWFtIHlldCwgYmFpbGluZy5cIiksUS53aGVuKG5ldyBNZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0KSk6KGU9cFtwLmxlbmd0aC0xXSxnPShlLnRmaW5pc2guZ2V0VGltZSgpLWUudHJlcXVlc3QuZ2V0VGltZSgpKS8xZTMsZj0oZS50ZmluaXNoLmdldFRpbWUoKS1lLnRyZXNwb25zZS5nZXRUaW1lKCkpLzFlMywwPj1nPyhvLmRlYnVnLmxvZyhcIkRvbid0IGtub3cgaG93IGxvbmcgdGhlIGRvd25sb2FkIG9mIHRoZSBsYXN0IGZyYWdtZW50IHRvb2ssIGJhaWxpbmcuXCIpLFEud2hlbihuZXcgTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdCkpOm51bGw9PT1lLm1lZGlhZHVyYXRpb258fHZvaWQgMD09PWUubWVkaWFkdXJhdGlvbnx8ZS5tZWRpYWR1cmF0aW9uPD0wPyhvLmRlYnVnLmxvZyhcIkRvbid0IGtub3cgdGhlIGR1cmF0aW9uIG9mIHRoZSBsYXN0IG1lZGlhIGZyYWdtZW50LCBiYWlsaW5nLlwiKSxRLndoZW4obmV3IE1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QpKTooaz1RLmRlZmVyKCksaT1lLm1lZGlhZHVyYXRpb24vZyxoPWUubWVkaWFkdXJhdGlvbi9mKnEsaXNOYU4oaCl8fGlzTmFOKGkpPyhvLmRlYnVnLmxvZyhcIlRvdGFsIHRpbWU6IFwiK2crXCJzXCIpLG8uZGVidWcubG9nKFwiRG93bmxvYWQgdGltZTogXCIrZitcInNcIiksby5kZWJ1Zy5sb2coXCJUaGUgcmF0aW9zIGFyZSBOYU4sIGJhaWxpbmcuXCIpLFEud2hlbihuZXcgTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdCkpOihvLmRlYnVnLmxvZyhcIlRvdGFsIHJhdGlvOiBcIitpKSxvLmRlYnVnLmxvZyhcIkRvd25sb2FkIHJhdGlvOiBcIitoKSxvLmRlYnVnLmxvZyhcIkRvd25sb2FkIHJhdGlvOiBcIitoKSxpc05hTihoKT8oby5kZWJ1Zy5sb2coXCJJbnZhbGlkIHJhdGlvLCBiYWlsaW5nLlwiKSxrLnJlc29sdmUobmV3IE1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QpKToxPmg/KG8uZGVidWcubG9nKFwiRG93bmxvYWQgcmF0aW8gaXMgcG9vci5cIiksYj4wPyhvLmRlYnVnLmxvZyhcIldlIGFyZSBub3QgYXQgdGhlIGxvd2VzdCBiaXRyYXRlLCBzbyBzd2l0Y2ggZG93bi5cIiksby5tYW5pZmVzdEV4dC5nZXRSZXByZXNlbnRhdGlvbkZvcihiLTEsZCkudGhlbihmdW5jdGlvbihhKXtvLm1hbmlmZXN0RXh0LmdldEJhbmR3aWR0aChhKS50aGVuKGZ1bmN0aW9uKGEpe28ubWFuaWZlc3RFeHQuZ2V0UmVwcmVzZW50YXRpb25Gb3IoYixkKS50aGVuKGZ1bmN0aW9uKGMpe28ubWFuaWZlc3RFeHQuZ2V0QmFuZHdpZHRoKGMpLnRoZW4oZnVuY3Rpb24oYyl7aj1hL2Msby5kZWJ1Zy5sb2coXCJTd2l0Y2ggcmF0aW86IFwiK2opLGo+aD8oby5kZWJ1Zy5sb2coXCJUaGluZ3MgbXVzdCBiZSBnb2luZyBwcmV0dHkgYmFkLCBzd2l0Y2ggYWxsIHRoZSB3YXkgZG93bi5cIiksay5yZXNvbHZlKG5ldyBNZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0KDApKSk6KG8uZGVidWcubG9nKFwiVGhpbmdzIGNvdWxkIGJlIGJldHRlciwgc28ganVzdCBzd2l0Y2ggZG93biBvbmUgaW5kZXguXCIpLGsucmVzb2x2ZShuZXcgTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdChiLTEpKSlcclxufSl9KX0pfSkpOihvLmRlYnVnLmxvZyhcIldlIGFyZSBhdCB0aGUgbG93ZXN0IGJpdHJhdGUgYW5kIGNhbm5vdCBzd2l0Y2ggZG93biwgdXNlIGN1cnJlbnQuXCIpLGsucmVzb2x2ZShuZXcgTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdChiKSkpKTooby5kZWJ1Zy5sb2coXCJEb3dubG9hZCByYXRpbyBpcyBnb29kLlwiKSxvLm1hbmlmZXN0RXh0LmdldFJlcHJlc2VudGF0aW9uQ291bnQoZCkudGhlbihmdW5jdGlvbihjKXtjLT0xLGM+Yj8oby5kZWJ1Zy5sb2coXCJXZSBhcmUgbm90IGF0IHRoZSBoaWdoZXN0IGJpdHJhdGUsIHNvIHN3aXRjaCB1cC5cIiksby5tYW5pZmVzdEV4dC5nZXRSZXByZXNlbnRhdGlvbkZvcihiKzEsZCkudGhlbihmdW5jdGlvbihlKXtvLm1hbmlmZXN0RXh0LmdldEJhbmR3aWR0aChlKS50aGVuKGZ1bmN0aW9uKGUpe28ubWFuaWZlc3RFeHQuZ2V0UmVwcmVzZW50YXRpb25Gb3IoYixkKS50aGVuKGZ1bmN0aW9uKGYpe28ubWFuaWZlc3RFeHQuZ2V0QmFuZHdpZHRoKGYpLnRoZW4oZnVuY3Rpb24oZil7aWYoaj1lL2Ysby5kZWJ1Zy5sb2coXCJTd2l0Y2ggcmF0aW86IFwiK2opLGg+PWopaWYoaD4xZTMpby5kZWJ1Zy5sb2coXCJUb25zIG9mIGJhbmR3aWR0aCBhdmFpbGFibGUsIGdvIGFsbCB0aGUgd2F5IHVwLlwiKSxrLnJlc29sdmUobmV3IE1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QoYy0xKSk7ZWxzZSBpZihoPjEwMClvLmRlYnVnLmxvZyhcIkp1c3QgZW5vdWdoIGJhbmR3aWR0aCBhdmFpbGFibGUsIHN3aXRjaCB1cCBvbmUuXCIpLGsucmVzb2x2ZShuZXcgTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdChiKzEpKTtlbHNle2ZvcihvLmRlYnVnLmxvZyhcIk5vdCBleGFjdGx5IHN1cmUgd2hlcmUgdG8gZ28sIHNvIGRvIHNvbWUgbWF0aC5cIiksbT0tMSxsPVtdOyhtKz0xKTxjOylsLnB1c2goYS5jYWxsKG8sbSxmLGQpKTtRLmFsbChsKS50aGVuKGZ1bmN0aW9uKGEpe2ZvcihtPTAsbj1hLmxlbmd0aDtuPm0mJiEoaDxhW21dKTttKz0xKTtvLmRlYnVnLmxvZyhcIkNhbGN1bGF0ZWQgaWRlYWwgbmV3IHF1YWxpdHkgaW5kZXggaXM6IFwiK20pLGsucmVzb2x2ZShuZXcgTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdChtKSl9KX1lbHNlIG8uZGVidWcubG9nKFwiTm90IGVub3VnaCBiYW5kd2lkdGggdG8gc3dpdGNoIHVwLlwiKSxrLnJlc29sdmUobmV3IE1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QpfSl9KX0pfSkpOihvLmRlYnVnLmxvZyhcIldlIGFyZSBhdCB0aGUgaGlnaGVzdCBiaXRyYXRlIGFuZCBjYW5ub3Qgc3dpdGNoIHVwLCB1c2UgY3VycmVudC5cIiksay5yZXNvbHZlKG5ldyBNZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0KGMpKSl9KSksay5wcm9taXNlKSkpOihvLmRlYnVnLmxvZyhcIk5vIG1ldHJpY3MsIGJhaWxpbmcuXCIpLFEud2hlbihuZXcgTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdCkpfX19LE1lZGlhUGxheWVyLnJ1bGVzLkRvd25sb2FkUmF0aW9SdWxlLnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIucnVsZXMuRG93bmxvYWRSYXRpb1J1bGV9LE1lZGlhUGxheWVyLnJ1bGVzLkluc3VmZmljaWVudEJ1ZmZlclJ1bGU9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt2YXIgYT0wLGI9MztyZXR1cm57ZGVidWc6dm9pZCAwLGNoZWNrSW5kZXg6ZnVuY3Rpb24oYyxkKXt2YXIgZSxmLGc9dGhpcyxoPSExLGk9TWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdC5wcm90b3R5cGUuREVGQVVMVDtyZXR1cm4gZy5kZWJ1Zy5sb2coXCJDaGVja2luZyBpbnN1ZmZpY2llbnQgYnVmZmVyIHJ1bGUuLi5cIiksbnVsbD09PWQuUGxheUxpc3R8fHZvaWQgMD09PWQuUGxheUxpc3R8fDA9PT1kLlBsYXlMaXN0Lmxlbmd0aD8oZy5kZWJ1Zy5sb2coXCJOb3QgZW5vdWdoIGluZm9ybWF0aW9uIGZvciBydWxlLlwiKSxRLndoZW4obmV3IE1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QpKTooZT1kLlBsYXlMaXN0W2QuUGxheUxpc3QubGVuZ3RoLTFdLG51bGw9PT1lfHx2b2lkIDA9PT1lfHwwPT09ZS50cmFjZS5sZW5ndGg/KGcuZGVidWcubG9nKFwiTm90IGVub3VnaCBpbmZvcm1hdGlvbiBmb3IgcnVsZS5cIiksUS53aGVuKG5ldyBNZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0KSk6KGY9ZS50cmFjZVtlLnRyYWNlLmxlbmd0aC0yXSxudWxsPT09Znx8dm9pZCAwPT09Znx8bnVsbD09PWYuc3RvcHJlYXNvbnx8dm9pZCAwPT09Zi5zdG9wcmVhc29uPyhnLmRlYnVnLmxvZyhcIk5vdCBlbm91Z2ggaW5mb3JtYXRpb24gZm9yIHJ1bGUuXCIpLFEud2hlbihuZXcgTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdCkpOihmLnN0b3ByZWFzb249PT1NZWRpYVBsYXllci52by5tZXRyaWNzLlBsYXlMaXN0LlRyYWNlLlJFQlVGRkVSSU5HX1JFQVNPTiYmKGg9ITAsYSs9MSxnLmRlYnVnLmxvZyhcIk51bWJlciBvZiB0aW1lcyB0aGUgYnVmZmVyIGhhcyBydW4gZHJ5OiBcIithKSksYT5iJiYoaT1NZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0LnByb3RvdHlwZS5TVFJPTkcsZy5kZWJ1Zy5sb2coXCJBcHBseSBTVFJPTkcgdG8gYnVmZmVyIHJ1bGUuXCIpKSxoPyhnLmRlYnVnLmxvZyhcIlRoZSBidWZmZXIgcmFuIGRyeSByZWNlbnRseSwgc3dpdGNoIGRvd24uXCIpLFEud2hlbihuZXcgTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdChjLTEsaSkpKTphPmI/KGcuZGVidWcubG9nKFwiVG9vIG1hbnkgZHJ5IGJ1ZmZlciBoaXRzLCBxdWl0IHN3aXRjaGluZyBiaXRyYXRlcy5cIiksUS53aGVuKG5ldyBNZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0KGMsaSkpKTpRLndoZW4obmV3IE1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QoTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdC5wcm90b3R5cGUuTk9fQ0hBTkdFLGkpKSkpKX19fSxNZWRpYVBsYXllci5ydWxlcy5JbnN1ZmZpY2llbnRCdWZmZXJSdWxlLnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIucnVsZXMuSW5zdWZmaWNpZW50QnVmZmVyUnVsZX0sTWVkaWFQbGF5ZXIucnVsZXMuTGltaXRTd2l0Y2hlc1J1bGU9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt2YXIgYT0xMCxiPTJlNCxjPTUsZD0wO3JldHVybntkZWJ1Zzp2b2lkIDAsY2hlY2tJbmRleDpmdW5jdGlvbihlLGYpe2lmKGQ+MClyZXR1cm4gZC09MSxRLndoZW4obmV3IE1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QoZSxNZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0LnByb3RvdHlwZS5TVFJPTkcpKTt2YXIgZyxoLGksaj10aGlzLGs9ITEsbD0obmV3IERhdGUpLmdldFRpbWUoKSxtPWYuUmVwU3dpdGNoTGlzdC5sZW5ndGg7Zm9yKGouZGVidWcubG9nKFwiQ2hlY2tpbmcgbGltaXQgc3dpdGNoZXMgcnVsZS4uLlwiKSxpPW0tMTtpPj0wO2ktPTEpe2lmKGc9Zi5SZXBTd2l0Y2hMaXN0W2ldLGg9bC1nLnQuZ2V0VGltZSgpLGg+PWIpe2ouZGVidWcubG9nKFwiUmVhY2hlZCB0aW1lIGxpbWl0LCBiYWlsaW5nLlwiKTticmVha31pZihpPj1hKXtqLmRlYnVnLmxvZyhcIkZvdW5kIHRvbyBtYW55IHN3aXRjaGVzIHdpdGhpbiB2YWxpZGF0aW9uIHRpbWUsIGZvcmNlIHRoZSBzdHJlYW0gdG8gbm90IGNoYW5nZS5cIiksaz0hMDticmVha319cmV0dXJuIGs/KGouZGVidWcubG9nKFwiV2FpdCBzb21lIHRpbWUgYmVmb3JlIGFsbG93aW5nIGFub3RoZXIgc3dpdGNoLlwiKSxkPWMsUS53aGVuKG5ldyBNZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0KGUsTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdC5wcm90b3R5cGUuU1RST05HKSkpOlEud2hlbihuZXcgTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdChNZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0LnByb3RvdHlwZS5OT19DSEFOR0UsTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdC5wcm90b3R5cGUuU1RST05HKSl9fX0sTWVkaWFQbGF5ZXIucnVsZXMuTGltaXRTd2l0Y2hlc1J1bGUucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci5ydWxlcy5MaW1pdFN3aXRjaGVzUnVsZX0sTWVkaWFQbGF5ZXIucnVsZXMuU3dpdGNoUmVxdWVzdD1mdW5jdGlvbihhLGIpe1widXNlIHN0cmljdFwiO3RoaXMucXVhbGl0eT1hLHRoaXMucHJpb3JpdHk9Yix2b2lkIDA9PT10aGlzLnF1YWxpdHkmJih0aGlzLnF1YWxpdHk9OTk5KSx2b2lkIDA9PT10aGlzLnByaW9yaXR5JiYodGhpcy5wcmlvcml0eT0uNSl9LE1lZGlhUGxheWVyLnJ1bGVzLlN3aXRjaFJlcXVlc3QucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci5ydWxlcy5Td2l0Y2hSZXF1ZXN0LE5PX0NIQU5HRTo5OTksREVGQVVMVDouNSxTVFJPTkc6MSxXRUFLOjB9LE1lZGlhUGxheWVyLm1vZGVscy5NZXRyaWNzTGlzdD1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3JldHVybntUY3BMaXN0OltdLEh0dHBMaXN0OltdLFJlcFN3aXRjaExpc3Q6W10sQnVmZmVyTGV2ZWw6W10sUGxheUxpc3Q6W10sRHJvcHBlZEZyYW1lczpbXX19LE1lZGlhUGxheWVyLm1vZGVscy5NZXRyaWNzTGlzdC5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOk1lZGlhUGxheWVyLm1vZGVscy5NZXRyaWNzTGlzdH0sTWVkaWFQbGF5ZXIudm8uU2VnbWVudFJlcXVlc3Q9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt0aGlzLmFjdGlvbj1cImRvd25sb2FkXCIsdGhpcy5zdGFydFRpbWU9MC8wLHRoaXMuc3RyZWFtVHlwZT1udWxsLHRoaXMudHlwZT1udWxsLHRoaXMuZHVyYXRpb249MC8wLHRoaXMudGltZXNjYWxlPTAvMCx0aGlzLnJhbmdlPW51bGwsdGhpcy51cmw9bnVsbCx0aGlzLnJlcXVlc3RTdGFydERhdGU9bnVsbCx0aGlzLmZpcnN0Qnl0ZURhdGU9bnVsbCx0aGlzLnJlcXVlc3RFbmREYXRlPW51bGwsdGhpcy5kZWZlcnJlZD1udWxsLHRoaXMucXVhbGl0eT0wLzAsdGhpcy5pbmRleD0wLzB9LE1lZGlhUGxheWVyLnZvLlNlZ21lbnRSZXF1ZXN0LnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIudm8uU2VnbWVudFJlcXVlc3QsQUNUSU9OX0RPV05MT0FEOlwiZG93bmxvYWRcIixBQ1RJT05fQ09NUExFVEU6XCJjb21wbGV0ZVwifSxNZWRpYVBsYXllci52by5tZXRyaWNzLkJ1ZmZlckxldmVsPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7dGhpcy50PW51bGwsdGhpcy5sZXZlbD1udWxsfSxNZWRpYVBsYXllci52by5tZXRyaWNzLkJ1ZmZlckxldmVsLnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIudm8ubWV0cmljcy5CdWZmZXJMZXZlbH0sTWVkaWFQbGF5ZXIudm8ubWV0cmljcy5Ecm9wcGVkRnJhbWVzPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7dGhpcy50aW1lPW51bGwsdGhpcy5kcm9wcGVkRnJhbWVzPW51bGx9LE1lZGlhUGxheWVyLnZvLm1ldHJpY3MuRHJvcHBlZEZyYW1lcy5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOk1lZGlhUGxheWVyLnZvLm1ldHJpY3MuRHJvcHBlZEZyYW1lc30sTWVkaWFQbGF5ZXIudm8ubWV0cmljcy5IVFRQUmVxdWVzdD1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3RoaXMudGNwaWQ9bnVsbCx0aGlzLnR5cGU9bnVsbCx0aGlzLnVybD1udWxsLHRoaXMuYWN0dWFsdXJsPW51bGwsdGhpcy5yYW5nZT1udWxsLHRoaXMudHJlcXVlc3Q9bnVsbCx0aGlzLnRyZXNwb25zZT1udWxsLHRoaXMudGZpbmlzaD1udWxsLHRoaXMucmVzcG9uc2Vjb2RlPW51bGwsdGhpcy5pbnRlcnZhbD1udWxsLHRoaXMubWVkaWFkdXJhdGlvbj1udWxsLHRoaXMudHJhY2U9W119LE1lZGlhUGxheWVyLnZvLm1ldHJpY3MuSFRUUFJlcXVlc3QucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci52by5tZXRyaWNzLkhUVFBSZXF1ZXN0fSxNZWRpYVBsYXllci52by5tZXRyaWNzLkhUVFBSZXF1ZXN0LlRyYWNlPWZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7dGhpcy5zPW51bGwsdGhpcy5kPW51bGwsdGhpcy5iPVtdfSxNZWRpYVBsYXllci52by5tZXRyaWNzLkhUVFBSZXF1ZXN0LlRyYWNlLnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIudm8ubWV0cmljcy5IVFRQUmVxdWVzdC5UcmFjZX0sTWVkaWFQbGF5ZXIudm8ubWV0cmljcy5QbGF5TGlzdD1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3RoaXMuc3RhcnQ9bnVsbCx0aGlzLm1zdGFydD1udWxsLHRoaXMuc3RhcnR0eXBlPW51bGwsdGhpcy50cmFjZT1bXX0sTWVkaWFQbGF5ZXIudm8ubWV0cmljcy5QbGF5TGlzdC5UcmFjZT1mdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3RoaXMucmVwcmVzZW50YXRpb25pZD1udWxsLHRoaXMuc3VicmVwbGV2ZWw9bnVsbCx0aGlzLnN0YXJ0PW51bGwsdGhpcy5tc3RhcnQ9bnVsbCx0aGlzLmR1cmF0aW9uPW51bGwsdGhpcy5wbGF5YmFja3NwZWVkPW51bGwsdGhpcy5zdG9wcmVhc29uPW51bGx9LE1lZGlhUGxheWVyLnZvLm1ldHJpY3MuUGxheUxpc3QucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci52by5tZXRyaWNzLlBsYXlMaXN0fSxNZWRpYVBsYXllci52by5tZXRyaWNzLlBsYXlMaXN0LklOSVRJQUxfUExBWV9TVEFSVF9SRUFTT049XCJpbml0aWFsX3N0YXJ0XCIsTWVkaWFQbGF5ZXIudm8ubWV0cmljcy5QbGF5TGlzdC5TRUVLX1NUQVJUX1JFQVNPTj1cInNlZWtcIixNZWRpYVBsYXllci52by5tZXRyaWNzLlBsYXlMaXN0LlRyYWNlLnByb3RvdHlwZT17Y29uc3RydWN0b3I6TWVkaWFQbGF5ZXIudm8ubWV0cmljcy5QbGF5TGlzdC5UcmFjZSgpfSxNZWRpYVBsYXllci52by5tZXRyaWNzLlBsYXlMaXN0LlRyYWNlLlVTRVJfUkVRVUVTVF9TVE9QX1JFQVNPTj1cInVzZXJfcmVxdWVzdFwiLE1lZGlhUGxheWVyLnZvLm1ldHJpY3MuUGxheUxpc3QuVHJhY2UuUkVQUkVTRU5UQVRJT05fU1dJVENIX1NUT1BfUkVBU09OPVwicmVwcmVzZW50YXRpb25fc3dpdGNoXCIsTWVkaWFQbGF5ZXIudm8ubWV0cmljcy5QbGF5TGlzdC5UcmFjZS5FTkRfT0ZfQ09OVEVOVF9TVE9QX1JFQVNPTj1cImVuZF9vZl9jb250ZW50XCIsTWVkaWFQbGF5ZXIudm8ubWV0cmljcy5QbGF5TGlzdC5UcmFjZS5SRUJVRkZFUklOR19SRUFTT049XCJyZWJ1ZmZlcmluZ1wiLE1lZGlhUGxheWVyLnZvLm1ldHJpY3MuUmVwcmVzZW50YXRpb25Td2l0Y2g9ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt0aGlzLnQ9bnVsbCx0aGlzLm10PW51bGwsdGhpcy50bz1udWxsLHRoaXMubHRvPW51bGx9LE1lZGlhUGxheWVyLnZvLm1ldHJpY3MuUmVwcmVzZW50YXRpb25Td2l0Y2gucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci52by5tZXRyaWNzLlJlcHJlc2VudGF0aW9uU3dpdGNofSxNZWRpYVBsYXllci52by5tZXRyaWNzLlRDUENvbm5lY3Rpb249ZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt0aGlzLnRjcGlkPW51bGwsdGhpcy5kZXN0PW51bGwsdGhpcy50b3Blbj1udWxsLHRoaXMudGNsb3NlPW51bGwsdGhpcy50Y29ubmVjdD1udWxsfSxNZWRpYVBsYXllci52by5tZXRyaWNzLlRDUENvbm5lY3Rpb24ucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpNZWRpYVBsYXllci52by5tZXRyaWNzLlRDUENvbm5lY3Rpb259OyJdLCJzb3VyY2VSb290IjoiL3NvdXJjZS8ifQ== diff --git a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Scripts/Lib/swfobject.js b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Scripts/Lib/swfobject.js index 8eafe9dd83f..296625bf455 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Scripts/Lib/swfobject.js +++ b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Scripts/Lib/swfobject.js @@ -1,4 +1,10 @@ +/* +** NOTE: This file is generated by Gulp and should not be edited directly! +** Any changes made directly to this file will be overwritten next time its asset group is processed by Gulp. +*/ + /* SWFObject v2.2 is released under the MIT License */ -var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='"+af+"";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='"+af+"";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;abProperties Microsoft.CloudMedia.Tests Microsoft.CloudMedia.Tests - v4.5 + v4.8 512 diff --git a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/CloudVideo.Edit.Assets.cshtml b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/CloudVideo.Edit.Assets.cshtml index b4b8a709900..572bd3a4b11 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/CloudVideo.Edit.Assets.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/CloudVideo.Edit.Assets.cshtml @@ -19,7 +19,7 @@ @helper MainFileUrl(Asset asset, Func mainFileUrl, string linkText) { if (!String.IsNullOrEmpty(mainFileUrl(asset))) { - @T(linkText) + @T.Encode(linkText) } } diff --git a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/CloudVideoEditor.Direct.cshtml b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/CloudVideoEditor.Direct.cshtml index a4d1b90d03f..4203b882685 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/CloudVideoEditor.Direct.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/CloudVideoEditor.Direct.cshtml @@ -71,14 +71,14 @@ @helper ThumbnailUpload(string caption) {
    - + @AsyncUpload("ThumbnailFile", Html.FieldNameFor(m => m.WamsThumbnail), Model.WamsThumbnail, allowedExtensions : null)
    } @helper SubtitleUpload(string caption) {
    - + @if (Model.SubtitleLanguages.Any()) { @AsyncUpload("SubtitleFile", Html.FieldNameFor(m => m.WamsSubtitle), Model.WamsSubtitle)
    diff --git a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/CloudVideoEditor.Proxied.cshtml b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/CloudVideoEditor.Proxied.cshtml index 9ef0865e05c..84945516c92 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/CloudVideoEditor.Proxied.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/CloudVideoEditor.Proxied.cshtml @@ -11,7 +11,7 @@
    - + @@ -36,7 +36,7 @@ @helper ThumbnailUpload(string caption) {
    - +
    } diff --git a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/EditorTemplates/Asset.Edit.Locators.cshtml b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/EditorTemplates/Asset.Edit.Locators.cshtml index ecf4139cf2e..d83c174a136 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/EditorTemplates/Asset.Edit.Locators.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Views/EditorTemplates/Asset.Edit.Locators.cshtml @@ -14,7 +14,7 @@ @foreach (var locator in locators) { - @T(locator.Name) + @T.Encode(locator.Name) @locator.Id @locator.Url diff --git a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Web.config b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Web.config index 246f2ed4766..2b930bf229e 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Web.config @@ -7,7 +7,7 @@ - + @@ -21,60 +21,75 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/packages.config b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/packages.config index 1e228049182..670821743e1 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/packages.config @@ -1,23 +1,30 @@  - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Constants.cs b/src/Orchard.Web/Modules/Orchard.Azure/Constants.cs index e7f6ea6e4f7..4d2af07c8b6 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/Constants.cs +++ b/src/Orchard.Web/Modules/Orchard.Azure/Constants.cs @@ -12,14 +12,5 @@ public class Constants { public const string MediaStorageContainerNameSettingName = "Orchard.Azure.Media.ContainerName"; public const string MediaStorageDefaultContainerName = "media"; // Container names must be lower case. public const string MediaStoragePublicHostName = "Orchard.Azure.Media.StoragePublicHostName"; - - public const string OutputCacheFeatureName = "Orchard.Azure.OutputCache"; - public const string OutputCacheSettingNamePrefix = "Orchard.Azure.OutputCache."; - public const string DatabaseCacheFeatureName = "Orchard.Azure.DatabaseCache"; - public const string DatabaseCacheSettingNamePrefix = "Orchard.Azure.DatabaseCache."; - - public const string CacheHostIdentifierSettingName = "HostIdentifier"; - public const string CacheCacheNameSettingName = "CacheName"; - public const string CacheAuthorizationTokenSettingName = "AuthorizationToken"; } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Module.txt b/src/Orchard.Web/Modules/Orchard.Azure/Module.txt index deefb6ec4f5..18c37dd75ab 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Azure/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Provides a set of Orchard service implementations targeting Microsoft Azure services. Category: Hosting Features: @@ -11,14 +11,4 @@ Features: Name: Microsoft Azure Media Storage Description: Activates an Orchard media storage provider that targets Microsoft Azure Blob Storage. Dependencies: Orchard.Azure - Category: Hosting - Orchard.Azure.OutputCache: - Name: Microsoft Azure Output Cache - Description: Activates an Orchard output cache provider that targets Windows Azure Cache. - Dependencies: Orchard.Azure, Orchard.OutputCache - Category: Performance - Orchard.Azure.DatabaseCache: - Name: Microsoft Azure Database Cache - Description: Activates an NHibernate second-level cache provider that targets Microsoft Azure Cache. - Dependencies: Orchard.Azure - Category: Performance + Category: Hosting diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj b/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj index cda10461df5..1eff9ded43c 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj +++ b/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj @@ -12,8 +12,8 @@ Properties Orchard.Azure Orchard.Azure - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -25,6 +25,7 @@ + true @@ -48,90 +49,104 @@ false - - ..\..\..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll - True + + ..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll - - ..\..\..\packages\log4net.2.0.3\lib\net40-full\log4net.dll - True + + ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll + + + ..\..\..\packages\log4net.2.0.12\lib\net45\log4net.dll + + + ..\..\..\packages\Microsoft.WindowsAzure.Caching.2.4.0.0\lib\net40-full\Microsoft.ApplicationServer.Caching.AzureClientHelper.dll + + + ..\..\..\packages\Microsoft.WindowsAzure.Caching.2.4.0.0\lib\net40-full\Microsoft.ApplicationServer.Caching.AzureCommon.dll + + + ..\..\..\packages\Microsoft.WindowsAzure.Caching.2.4.0.0\lib\net40-full\Microsoft.ApplicationServer.Caching.Client.dll + + + ..\..\..\packages\Microsoft.WindowsAzure.Caching.2.4.0.0\lib\net40-full\Microsoft.ApplicationServer.Caching.Core.dll ..\..\..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll - True - - ..\..\..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll - True + + + ..\..\..\packages\Microsoft.Data.Edm.5.8.4\lib\net40\Microsoft.Data.Edm.dll - - ..\..\..\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll - True + + ..\..\..\packages\Microsoft.Data.OData.5.8.4\lib\net40\Microsoft.Data.OData.dll - - ..\..\..\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll - True + + ..\..\..\packages\Microsoft.Data.Services.Client.5.8.4\lib\net40\Microsoft.Data.Services.Client.dll + + + ..\..\..\packages\Microsoft.WindowsAzure.Caching.2.4.0.0\lib\net40-full\Microsoft.Web.DistributedCache.dll ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True ..\..\..\packages\Microsoft.WindowsAzure.ConfigurationManager.3.1.0\lib\net40\Microsoft.WindowsAzure.Configuration.dll - True ..\..\..\packages\Orchard.WindowsAzure.ServiceRuntime.2.7.0.0\lib\Microsoft.WindowsAzure.ServiceRuntime.dll - True ..\..\..\packages\WindowsAzure.Storage.5.0.2\lib\net40\Microsoft.WindowsAzure.Storage.dll - True - - ..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True + + ..\..\..\packages\Microsoft.WindowsAzure.Caching.2.4.0.0\lib\net40-full\Microsoft.WindowsFabric.Common.dll + + + ..\..\..\packages\Microsoft.WindowsAzure.Caching.2.4.0.0\lib\net40-full\Microsoft.WindowsFabric.Data.Common.dll + + + ..\..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll + + + ..\..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll - - ..\..\..\packages\NHibernate.4.0.1.4000\lib\net40\NHibernate.dll - True + + ..\..\..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll - - ..\..\..\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll - True + + + ..\..\..\packages\System.Spatial.5.8.4\lib\net40\System.Spatial.dll + - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -148,7 +163,7 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) @@ -159,7 +174,7 @@ - + 10.0 @@ -185,7 +200,7 @@ --> - + @@ -199,10 +214,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Azure/Properties/AssemblyInfo.cs index ea8efe11ce4..2ca10a1180e 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Azure/Properties/AssemblyInfo.cs @@ -31,6 +31,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Services/FileSystems/AzureFileSystem.cs b/src/Orchard.Web/Modules/Orchard.Azure/Services/FileSystems/AzureFileSystem.cs index f10dfc9bf2f..f4d586b2471 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/Services/FileSystems/AzureFileSystem.cs +++ b/src/Orchard.Web/Modules/Orchard.Azure/Services/FileSystems/AzureFileSystem.cs @@ -96,6 +96,8 @@ private static string ConvertToRelativeUriPath(string path) { return newPath; } + private static string GetFolderName(string path) => path.Substring(path.LastIndexOf('/') + 1); + public string Combine(string path1, string path2) { if (path1 == null) { throw new ArgumentNullException("path1"); @@ -148,10 +150,10 @@ public IEnumerable ListFiles(string path) { } return BlobClient.ListBlobs(prefix) - .OfType() - .Where(blobItem => !blobItem.Uri.AbsoluteUri.EndsWith(FolderEntry)) - .Select(blobItem => new AzureBlobFileStorage(blobItem, _absoluteRoot)) - .ToArray(); + .OfType() + .Where(blobItem => !blobItem.Uri.AbsoluteUri.EndsWith(FolderEntry)) + .Select(blobItem => new AzureBlobFileStorage(blobItem, _absoluteRoot)) + .ToArray(); } public IEnumerable ListFolders(string path) { @@ -201,6 +203,11 @@ public bool TryCreateFolder(string path) { public void CreateFolder(string path) { path = ConvertToRelativeUriPath(path); + + if (FileSystemStorageProvider.FolderNameContainsInvalidCharacters(GetFolderName(path))) { + throw new InvalidNameCharacterException("The directory name contains invalid character(s)"); + } + Container.EnsureDirectoryDoesNotExist(String.Concat(_root, path)); // Creating a virtually hidden file to make the directory an existing concept @@ -232,6 +239,20 @@ public void RenameFolder(string path, string newPath) { path = ConvertToRelativeUriPath(path); newPath = ConvertToRelativeUriPath(newPath); + if (FileSystemStorageProvider.FolderNameContainsInvalidCharacters(GetFolderName(newPath))) { + throw new InvalidNameCharacterException("The new directory name contains invalid character(s)"); + } + + // Workaround for https://github.com/Azure/azure-storage-net/issues/892. + // Renaming a folder by only changing the casing corrupts all the files in the folder. + if (path.Equals(newPath, StringComparison.OrdinalIgnoreCase)) { + var tempPath = Guid.NewGuid().ToString() + "/"; + + RenameFolder(path, tempPath); + + path = tempPath; + } + if (!path.EndsWith("/")) path += "/"; @@ -246,7 +267,8 @@ public void RenameFolder(string path, string newPath) { } if (blob is CloudBlobDirectory) { - string foldername = blob.Uri.Segments.Last(); + var blobDir = (CloudBlobDirectory)blob; + string foldername = blobDir.Prefix.Substring(blobDir.Parent.Prefix.Length); string source = String.Concat(path, foldername); string destination = String.Concat(newPath, foldername); RenameFolder(source, destination); @@ -266,6 +288,10 @@ public void RenameFile(string path, string newPath) { path = ConvertToRelativeUriPath(path); newPath = ConvertToRelativeUriPath(newPath); + if (FileSystemStorageProvider.FileNameContainsInvalidCharacters(Path.GetFileName(newPath))) { + throw new InvalidNameCharacterException("The new file name contains invalid character(s)"); + } + Container.EnsureBlobExists(String.Concat(_root, path)); Container.EnsureBlobDoesNotExist(String.Concat(_root, newPath)); @@ -290,6 +316,10 @@ public void CopyFile(string path, string newPath) { public IStorageFile CreateFile(string path) { path = ConvertToRelativeUriPath(path); + if (FileSystemStorageProvider.FileNameContainsInvalidCharacters(Path.GetFileName(path))) { + throw new InvalidNameCharacterException("The file name contains invalid character(s)"); + } + if (Container.BlobExists(String.Concat(_root, path))) { throw new ArgumentException("File " + path + " already exists"); } @@ -377,10 +407,7 @@ public AzureBlobFolderStorage(CloudBlobDirectory blob, string rootPath) { _rootPath = rootPath; } - public string GetName() { - var path = GetPath(); - return path.Substring(path.LastIndexOf('/') + 1); - } + public string GetName() => GetFolderName(GetPath()); public string GetPath() { return _blob.Uri.ToString().Substring(_rootPath.Length).Trim('/'); @@ -405,11 +432,12 @@ private static long GetDirectorySize(CloudBlobDirectory directoryBlob) { long size = 0; foreach (var blobItem in directoryBlob.ListBlobs()) { - if (blobItem is CloudBlockBlob) - size += ((CloudBlockBlob)blobItem).Properties.Length; - - if (blobItem is CloudBlobDirectory) - size += GetDirectorySize((CloudBlobDirectory)blobItem); + if (blobItem is CloudBlockBlob blob) { + size += blob.Properties.Length; + } + else if (blobItem is CloudBlobDirectory directory) { + size += GetDirectorySize(directory); + } } return size; diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Services/FileSystems/Media/AzureBlobStorageProvider.cs b/src/Orchard.Web/Modules/Orchard.Azure/Services/FileSystems/Media/AzureBlobStorageProvider.cs index 483e77259da..e615af2ab83 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/Services/FileSystems/Media/AzureBlobStorageProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Azure/Services/FileSystems/Media/AzureBlobStorageProvider.cs @@ -1,10 +1,11 @@ -using System.IO; +using System; +using System.IO; +using System.Linq; using System.Web; using Orchard.Azure.Services.Environment.Configuration; using Orchard.Environment.Configuration; using Orchard.Environment.Extensions; using Orchard.FileSystems.Media; -using System; namespace Orchard.Azure.Services.FileSystems.Media { @@ -20,8 +21,7 @@ public AzureBlobStorageProvider( platformConfigurationAccessor.GetSetting(Constants.MediaStorageContainerNameSettingName, shellSettings.Name, null) ?? Constants.MediaStorageDefaultContainerName, platformConfigurationAccessor.GetSetting(Constants.MediaStorageRootFolderPathSettingName, shellSettings.Name, null) ?? shellSettings.Name, mimeTypeProvider, - platformConfigurationAccessor.GetSetting(Constants.MediaStoragePublicHostName, shellSettings.Name, null)) - { + platformConfigurationAccessor.GetSetting(Constants.MediaStoragePublicHostName, shellSettings.Name, null)) { } public AzureBlobStorageProvider(string storageConnectionString, string containerName, string rootFolderPath, IMimeTypeProvider mimeTypeProvider, string publicHostName) @@ -67,7 +67,7 @@ public string GetStoragePath(string url) { EnsureInitialized(); var rootUri = new Uri(_absoluteRoot); var uri = new Uri(url); - if((uri.Host == rootUri.Host || (!string.IsNullOrEmpty(_publicHostName) && uri.Host == _publicHostName)) && uri.AbsolutePath.StartsWith(rootUri.AbsolutePath)) { + if ((uri.Host == rootUri.Host || (!string.IsNullOrEmpty(_publicHostName) && uri.Host == _publicHostName)) && uri.AbsolutePath.StartsWith(rootUri.AbsolutePath)) { return HttpUtility.UrlDecode(uri.PathAndQuery.Substring(Combine(rootUri.AbsolutePath, "/").Length)); } @@ -77,5 +77,45 @@ public string GetStoragePath(string url) { public string GetRelativePath(string path) { return GetPublicUrl(path); } + + public new void DeleteFile(string path) { + DeleteFileProfiles(path); + + base.DeleteFile(path); + } + + + /// + /// Cleans up files generated by Media Profiles for a specific file. + /// + /// The full path and name of a file. + private void DeleteFileProfiles(string path) { + if (FolderExists("_Profiles")) { + // The children of the "_Profiles" folder correspond to specific Media Profiles. + var profileFolderPaths = ListFolders("_Profiles").Select(folder => folder.GetPath()); + if (profileFolderPaths.Any()) { + var filenameWithExtension = GetFile(path)?.GetName() ?? ""; + var publicUrl = GetPublicUrl(path); + var originalFullPath = publicUrl.Substring(0, publicUrl.Length - filenameWithExtension.Length); + // This identifies the child folder of the specific Profile Media folder, + // containing the files generated from the same path. + var pathHash = originalFullPath.GetHashCode().ToString("x").ToLowerInvariant(); + + string fullPath, fullName; + // Checking each Media Profile's folder. + foreach (var profileFolderPath in profileFolderPaths) { + fullPath = Combine(profileFolderPath, pathHash); + fullName = Combine(fullPath, filenameWithExtension); + + // Deleting the file generated for the current Media Profile. + if (FileExists(fullName)) base.DeleteFile(fullName); + + // If the current path's Media Profile folder hasn't got any more generated files, + // then it can be deleted too. + if (!ListFiles(fullPath).Any()) DeleteFolder(fullPath); + } + } + } + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Web.config b/src/Orchard.Web/Modules/Orchard.Azure/Web.config index 2109400903c..af1baefa515 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Azure/Web.config @@ -5,9 +5,9 @@
    - +
    - + @@ -22,72 +22,98 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Azure/packages.config b/src/Orchard.Web/Modules/Orchard.Azure/packages.config index 6b83756e980..909cc51f835 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Azure/packages.config @@ -1,19 +1,23 @@  - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/AdminMenu.cs b/src/Orchard.Web/Modules/Orchard.Blogs/AdminMenu.cs index 090905c5d74..4460dc8472a 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/AdminMenu.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/AdminMenu.cs @@ -1,5 +1,6 @@ using System.Linq; using Orchard.Blogs.Services; +using Orchard.ContentManagement; using Orchard.Localization; using Orchard.Security; using Orchard.UI.Navigation; @@ -26,7 +27,7 @@ public void GetNavigation(NavigationBuilder builder) { } private void BuildMenu(NavigationItemBuilder menu) { - var blogs = _blogService.Get().Where(x => _authorizationService.TryCheckAccess(Permissions.MetaListBlogs, _workContextAccessor.GetContext().CurrentUser, x)).ToArray(); + var blogs = _blogService.Get(VersionOptions.Latest).Where(x => _authorizationService.TryCheckAccess(Permissions.MetaListBlogs, _workContextAccessor.GetContext().CurrentUser, x)).ToArray(); var blogCount = blogs.Count(); var singleBlog = blogCount == 1 ? blogs.ElementAt(0) : null; @@ -41,7 +42,7 @@ private void BuildMenu(NavigationItemBuilder menu) { if (singleBlog != null) menu.Add(T("New Post"), "1.1", item => - item.Action("Create", "BlogPostAdmin", new {area = "Orchard.Blogs", blogId = singleBlog.Id}).Permission(Permissions.MetaListOwnBlogs)); + item.Action("Create", "BlogPostAdmin", new { area = "Orchard.Blogs", blogId = singleBlog.Id }).Permission(Permissions.MetaListOwnBlogs)); menu.Add(T("New Blog"), "1.2", item => diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/BlogPostLocalNavigationProvider.cs b/src/Orchard.Web/Modules/Orchard.Blogs/BlogPostLocalNavigationProvider.cs new file mode 100644 index 00000000000..5e20fbdaa24 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Blogs/BlogPostLocalNavigationProvider.cs @@ -0,0 +1,40 @@ +using Orchard.Blogs.Services; +using Orchard.Localization; +using Orchard.Security; +using Orchard.UI.Navigation; + +namespace Orchard.Blogs { + public class BlogPostsLocalNavigationProvider : INavigationProvider { + private readonly IBlogService _blogService; + private readonly IAuthorizationService _authorizationService; + private readonly IWorkContextAccessor _workContextAccessor; + + public BlogPostsLocalNavigationProvider( + IBlogService blogService, + IAuthorizationService authorizationService, + IWorkContextAccessor workContextAccessor) { + + T = NullLocalizer.Instance; + _blogService = blogService; + _authorizationService = authorizationService; + _workContextAccessor = workContextAccessor; + } + + public Localizer T { get; set; } + + public string MenuName { + get { return "blogposts-navigation"; } + } + + public void GetNavigation(NavigationBuilder builder) { + var blogId = 0; + int.TryParse(_workContextAccessor.GetContext().HttpContext.Request.RequestContext.RouteData.Values["blogId"]?.ToString(), out blogId); + if (blogId > 0) { + builder.Add(T("Blog posts"), + item => item.Action("Item", "BlogAdmin", new { area = "Orchard.Blogs", blogId }) + .LocalNav() + .Permission(Permissions.MetaListOwnBlogs)); + } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/BlogsLocalizationExtensions/Handlers/BlogPostPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Blogs/BlogsLocalizationExtensions/Handlers/BlogPostPartHandler.cs new file mode 100644 index 00000000000..67305291737 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Blogs/BlogsLocalizationExtensions/Handlers/BlogPostPartHandler.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using System.Linq; +using System.Web.Routing; + +using Orchard.Autoroute.Models; +using Orchard.Autoroute.Services; +using Orchard.Blogs.Models; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Aspects; +using Orchard.ContentManagement.Handlers; +using Orchard.Core.Common.Models; +using Orchard.Core.Title.Models; +using Orchard.Environment.Extensions; +using Orchard.Localization; +using Orchard.Localization.Models; +using Orchard.Localization.Services; +using Orchard.UI.Notify; + +namespace Orchard.Blogs.BlogsLocalizationExtensions.Handlers { + [OrchardFeature("Orchard.Blogs.LocalizationExtensions")] + public class BlogPostPartHandler : ContentHandler { + private readonly IContentManager _contentManager; + private readonly IAutorouteService _routeService; + private readonly ILocalizationService _localizationService; + + public BlogPostPartHandler(RequestContext requestContext, IContentManager contentManager, IAutorouteService routeService, ILocalizationService localizationService, INotifier notifier) { + _contentManager = contentManager; + _routeService = routeService; + _localizationService = localizationService; + Notifier = notifier; + T = NullLocalizer.Instance; + //move posts when created, updated or published + //changed OnCreating and OnUpdating in OnCreated and OnUpdated so LocalizationPart is already populated + OnCreated((context, part) => MigrateBlogPost(context.ContentItem)); + OnUpdated((context, part) => MigrateBlogPost(context.ContentItem)); + OnPublishing((context, part) => MigrateBlogPost(context.ContentItem)); + } + + public INotifier Notifier { get; set; } + + public Localizer T { get; set; } + + //This Method checks the blog post's culture and it's parent blog's culture and moves it to the correct blog if they aren't equal. + private void MigrateBlogPost(ContentItem blogPost) { + if (!blogPost.Has() || !blogPost.Has()) { + return; + } + //bolgPost just cloned for translation, never saved + if (blogPost.As().Container == null) { + return; + } + var blog = _contentManager.Get(blogPost.As().Container.Id); + if (!blog.Has() || blog.As().Culture == null) { + return; + } + + //get our 2 cultures for comparison + var blogCulture = blog.As().Culture; + var blogPostCulture = blogPost.As().Culture; + + //if the post is a different culture than the parent blog change the post's parent blog to the right localization... + if (blogPostCulture != null && (blogPostCulture.Id != blogCulture.Id)) { + //Get the id of the current blog + var blogids = new HashSet { blog.As().ContentItem.Id }; + + //seek for same culture blog + var realBlog = _localizationService.GetLocalizations(blog) + .SingleOrDefault(w => w.Culture?.Culture == blogPostCulture.Culture); + if (realBlog.Has() && realBlog.As().Culture.Id == blogPostCulture.Id) { + blogPost.As().Container = realBlog; + if (blogPost.Has()) { + _routeService.RemoveAliases(blogPost.As()); + blogPost.As().DisplayAlias = _routeService.GenerateAlias(blogPost.As()); + _routeService.PublishAlias(blogPost.As()); + } + Notifier.Information(T("Your Post has been moved under the \"{0}\" Blog", realBlog.As().Title)); + return; + } + + return; + } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/BlogsLocalizationExtensions/Migrations/Migrations.cs b/src/Orchard.Web/Modules/Orchard.Blogs/BlogsLocalizationExtensions/Migrations/Migrations.cs new file mode 100644 index 00000000000..962b10cf632 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Blogs/BlogsLocalizationExtensions/Migrations/Migrations.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using Orchard.ContentManagement.MetaData; +using Orchard.Data.Migration; +using Orchard.Environment.Extensions; + +namespace Orchard.Blogs.BlogsLocalizationExtensions.Migrations { + [OrchardFeature("Orchard.Blogs.LocalizationExtensions")] + public class Migrations : DataMigrationImpl { + public int Create() { + ContentDefinitionManager.AlterTypeDefinition("Blog", + cfg => cfg + .WithPart("LocalizationPart")); + ContentDefinitionManager.AlterTypeDefinition("BlogPost", + cfg => cfg + .WithPart("LocalizationPart")); + return 1; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs index ea7fe53aa2b..8455f926368 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs @@ -2,7 +2,6 @@ using System.Web.Mvc; using Orchard.Blogs.Extensions; using Orchard.Blogs.Models; -using Orchard.Blogs.Routing; using Orchard.Blogs.Services; using Orchard.ContentManagement; using Orchard.Data; @@ -13,6 +12,7 @@ using Orchard.UI.Navigation; using Orchard.UI.Notify; using Orchard.Settings; +using System.Collections.Generic; namespace Orchard.Blogs.Controllers { @@ -21,6 +21,7 @@ public class BlogAdminController : Controller, IUpdateModel { private readonly IBlogService _blogService; private readonly IBlogPostService _blogPostService; private readonly IContentManager _contentManager; + private readonly INavigationManager _navigationManager; private readonly ITransactionManager _transactionManager; private readonly ISiteService _siteService; @@ -29,6 +30,7 @@ public BlogAdminController( IBlogService blogService, IBlogPostService blogPostService, IContentManager contentManager, + INavigationManager navigationManager, ITransactionManager transactionManager, ISiteService siteService, IShapeFactory shapeFactory) { @@ -36,6 +38,7 @@ public BlogAdminController( _blogService = blogService; _blogPostService = blogPostService; _contentManager = contentManager; + _navigationManager = navigationManager; _transactionManager = transactionManager; _siteService = siteService; T = NullLocalizer.Instance; @@ -101,14 +104,14 @@ public ActionResult EditDeletePOST(int blogId) { return HttpNotFound(); _blogService.Delete(blog); - Services.Notifier.Success(T("Blog deleted")); + Services.Notifier.Success(T("Blog was deleted.")); return Redirect(Url.BlogsForAdmin()); } [HttpPost, ActionName("Edit")] - [FormValueRequired("submit.Save")] + [FormValueRequired("submit.Publish")] public ActionResult EditPOST(int blogId) { var blog = _blogService.Get(blogId, VersionOptions.DraftRequired); @@ -125,7 +128,7 @@ public ActionResult EditPOST(int blogId) { } _contentManager.Publish(blog); - Services.Notifier.Success(T("Blog information updated")); + Services.Notifier.Success(T("Blog properties were updated.")); return Redirect(Url.BlogsForAdmin()); } @@ -142,7 +145,7 @@ public ActionResult Remove(int blogId) { _blogService.Delete(blog); - Services.Notifier.Success(T("Blog was successfully deleted")); + Services.Notifier.Success(T("Blog was successfully deleted.")); return Redirect(Url.BlogsForAdmin()); } @@ -151,10 +154,10 @@ public ActionResult List() { list.AddRange(_blogService.Get(VersionOptions.Latest) .Where(x => Services.Authorizer.Authorize(Permissions.MetaListOwnBlogs, x)) .Select(b => { - var blog = Services.ContentManager.BuildDisplay(b, "SummaryAdmin"); - blog.TotalPostCount = _blogPostService.PostCount(b, VersionOptions.Latest); - return blog; - })); + var blog = Services.ContentManager.BuildDisplay(b, "SummaryAdmin"); + blog.TotalPostCount = _blogPostService.PostCount(b, VersionOptions.Latest); + return blog; + })); var viewModel = Services.New.ViewModel() .ContentItems(list); @@ -179,6 +182,18 @@ public ActionResult Item(int blogId, PagerParameters pagerParameters) { var totalItemCount = _blogPostService.PostCount(blogPart, VersionOptions.Latest); blog.Content.Add(Shape.Pager(pager).TotalItemCount(totalItemCount), "Content:after"); + // Adds LocalMenus; + var menuItems = _navigationManager.BuildMenu("blogposts-navigation"); + var request = Services.WorkContext.HttpContext.Request; + + // Set the currently selected path + Stack selectedPath = NavigationHelper.SetSelectedPath(menuItems, request, request.RequestContext.RouteData); + + // Populate local nav + dynamic localMenuShape = Shape.LocalMenu().MenuName("local-admin"); + // NavigationHelper.PopulateLocalMenu(Shape, localMenuShape, localMenuShape, selectedPath); + NavigationHelper.PopulateLocalMenu(Shape, localMenuShape, localMenuShape, menuItems); + Services.WorkContext.Layout.LocalNavigation.Add(localMenuShape); return View(blog); } diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogPostAdminController.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogPostAdminController.cs index 9a3a46c3fa7..0e8bdca1c2c 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogPostAdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogPostAdminController.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Reflection; using System.Web.Mvc; using Orchard.Blogs.Extensions; @@ -98,6 +99,18 @@ private ActionResult CreatePOST(int blogId, bool publish = false) { return Redirect(Url.BlogPostEdit(blogPost)); } + public ActionResult CreateWithoutBlog() { + var blogs = _blogService.Get().ToArray(); + + if (blogs.Count() == 0) { + Services.Notifier.Warning(T("To create a BlogPost you need to create a blog first. You have been redirected to the Blog creation page.")); + return RedirectToAction("Create", "BlogAdmin", new { area = "Orchard.Blogs" }); + } else { + Services.Notifier.Warning(T("To create a BlogPost you need to choose a blog first. You have been redirected to the Blog selection page.")); + return RedirectToAction("List", "BlogAdmin", new { area = "Orchard.Blogs" }); + } + } + //todo: the content shape template has extra bits that the core contents module does not (remove draft functionality) //todo: - move this extra functionality there or somewhere else that's appropriate? public ActionResult Edit(int blogId, int postId) { diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogPostController.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogPostController.cs index a1cacc50d8f..7d26c3193e1 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogPostController.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogPostController.cs @@ -9,7 +9,9 @@ using Orchard.DisplayManagement; using Orchard.Localization; using Orchard.Mvc; +using Orchard.Settings; using Orchard.Themes; +using Orchard.UI.Navigation; namespace Orchard.Blogs.Controllers { [Themed] @@ -19,19 +21,22 @@ public class BlogPostController : Controller { private readonly IBlogPostService _blogPostService; private readonly IFeedManager _feedManager; private readonly IArchiveConstraint _archiveConstraint; - + private readonly ISiteService _siteService; + public BlogPostController( IOrchardServices services, IBlogService blogService, IBlogPostService blogPostService, IFeedManager feedManager, IShapeFactory shapeFactory, - IArchiveConstraint archiveConstraint) { + IArchiveConstraint archiveConstraint, + ISiteService siteService) { _services = services; _blogService = blogService; _blogPostService = blogPostService; _feedManager = feedManager; _archiveConstraint = archiveConstraint; + _siteService = siteService; T = NullLocalizer.Instance; Shape = shapeFactory; } @@ -39,7 +44,8 @@ public BlogPostController( dynamic Shape { get; set; } public Localizer T { get; set; } - public ActionResult ListByArchive(string path) { + public ActionResult ListByArchive(string path, PagerParameters pagerParameters) { + Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters); var blogPath = _archiveConstraint.FindPath(path); var archive = _archiveConstraint.FindArchiveData(path); @@ -60,15 +66,21 @@ public ActionResult ListByArchive(string path) { return new ShapeResult(this, Shape.Parts_Blogs_BlogArchives(Blog: blogPart, Archives: _blogPostService.GetArchives(blogPart))); } + pager.PageSize = blogPart.PostsPerPage; + var list = Shape.List(); - list.AddRange(_blogPostService.Get(blogPart, archive).Select(b => _services.ContentManager.BuildDisplay(b, "Summary"))); + list.AddRange(_blogPostService.Get(blogPart, archive, pager.GetStartIndex(), pager.PageSize) + .Select(b => _services.ContentManager.BuildDisplay(b, "Summary"))); + + var totalItemCount = _blogPostService.Get(blogPart, archive).Count(); _feedManager.Register(blogPart, _services.ContentManager.GetItemMetadata(blogPart).DisplayText); var viewModel = Shape.ViewModel() .ContentItems(list) .Blog(blogPart) - .ArchiveData(archive); + .ArchiveData(archive) + .Pager(Shape.Pager(pager).TotalItemCount(totalItemCount)); return View(viewModel); } diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Drivers/BlogPostPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Drivers/BlogPostPartDriver.cs index fb5f2ccdac4..37af7a5c85d 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Drivers/BlogPostPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Drivers/BlogPostPartDriver.cs @@ -1,5 +1,5 @@ -using Orchard.Blogs.Models; -using Orchard.Blogs.Extensions; +using Orchard.Blogs.Extensions; +using Orchard.Blogs.Models; using Orchard.ContentManagement; using Orchard.ContentManagement.Drivers; using Orchard.Core.Feeds; @@ -15,11 +15,13 @@ public BlogPostPartDriver(IFeedManager feedManager, IContentManager contentManag } protected override DriverResult Display(BlogPostPart part, string displayType, dynamic shapeHelper) { - if (displayType.StartsWith("Detail")) { - var blogTitle = _contentManager.GetItemMetadata(part.BlogPart).DisplayText; - _feedManager.Register(part.BlogPart, blogTitle); + if (part.BlogPart != null && part.BlogPart.HasPublished()) { + if (displayType.StartsWith("Detail")) { + var publishedBlog = part.BlogPart.IsPublished() ? part.BlogPart : _contentManager.Get(part.BlogPart.Id).As(); + var blogTitle = _contentManager.GetItemMetadata(publishedBlog).DisplayText; + _feedManager.Register(publishedBlog, blogTitle); + } } - return null; } } diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPartArchiveHandler.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPartArchiveHandler.cs index 3a53ceddbb0..5b3b0449436 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPartArchiveHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPartArchiveHandler.cs @@ -15,10 +15,10 @@ public class BlogPartArchiveHandler : ContentHandler { private readonly IWorkContextAccessor _workContextAccessor; private readonly IContentManager _contentManager; // contains the creation time of a blog part before it has been changed - private readonly Dictionary _previousCreatedUtc = new Dictionary(); + private readonly Dictionary _previousCreatedUtc = new Dictionary(); public BlogPartArchiveHandler( - IRepository blogArchiveRepository, + IRepository blogArchiveRepository, IBlogPostService blogPostService, IWorkContextAccessor workContextAccessor, IContentManager contentManager) { @@ -26,11 +26,11 @@ public BlogPartArchiveHandler( _workContextAccessor = workContextAccessor; _contentManager = contentManager; - OnUpdating((context, cp) => { if(context.ContentItem.Has()) SavePreviousCreatedDate(context.Id);}); + OnUpdating((context, cp) => { if (context.ContentItem.Has()) SavePreviousCreatedDate(context.Id); }); OnRemoving((context, bp) => SavePreviousCreatedDate(context.Id)); OnUnpublishing((context, bp) => SavePreviousCreatedDate(context.Id)); - OnPublished((context, bp) => IncreaseBlogArchive(bp)); + OnPublished((context, bp) => ManageBlogArchiveSync(bp)); OnUnpublished((context, bp) => ReduceBlogArchive(bp)); OnRemoved((context, bp) => ReduceBlogArchive(bp)); } @@ -71,58 +71,56 @@ private void ReduceBlogArchive(BlogPostPart blogPostPart) { && x.Month == datetime.Month && x.Year == datetime.Year); - if(previousArchiveRecord == null) + if (previousArchiveRecord == null) return; if (previousArchiveRecord.PostCount > 1) previousArchiveRecord.PostCount--; else _blogArchiveRepository.Delete(previousArchiveRecord); + + blogPostPart.ArchiveSync = null; } + private void ReduceBlogArchiveByDate(int BlogPartId, DateTime? dateBlogPost) { + _blogArchiveRepository.Flush(); + + if (BlogPartId!= 0 && dateBlogPost.HasValue) { + var previousArchiveRecord = _blogArchiveRepository.Table + .FirstOrDefault(x => x.BlogPart.Id == BlogPartId + && x.Month == dateBlogPost.Value.Month + && x.Year == dateBlogPost.Value.Year); + + if (previousArchiveRecord == null) + return; + + if (previousArchiveRecord.PostCount > 1) + previousArchiveRecord.PostCount--; + else + _blogArchiveRepository.Delete(previousArchiveRecord); + } + else { + return; + } + + } + private void IncreaseBlogArchive(BlogPostPart blogPostPart) { _blogArchiveRepository.Flush(); - + var commonPart = blogPostPart.As(); - if(commonPart == null || !commonPart.CreatedUtc.HasValue) + if (commonPart == null || !commonPart.CreatedUtc.HasValue) return; // get the time zone for the current request var timeZone = _workContextAccessor.GetContext().CurrentTimeZone; - var previousCreatedUtc = _previousCreatedUtc.ContainsKey(blogPostPart.Id) ? _previousCreatedUtc[blogPostPart.Id] : DateTime.MinValue; - previousCreatedUtc = TimeZoneInfo.ConvertTimeFromUtc(previousCreatedUtc, timeZone); - - var previousMonth = previousCreatedUtc.Month; - var previousYear = previousCreatedUtc.Year; - var newCreatedUtc = commonPart.CreatedUtc; newCreatedUtc = TimeZoneInfo.ConvertTimeFromUtc(newCreatedUtc.Value, timeZone); var newMonth = newCreatedUtc.Value.Month; var newYear = newCreatedUtc.Value.Year; - // if archives are the same there is nothing to do - if (previousMonth == newMonth && previousYear == newYear) { - return; - } - - // decrement previous archive record - var previousArchiveRecord = _blogArchiveRepository - .Table - .FirstOrDefault(x => x.BlogPart.Id == blogPostPart.BlogPart.Id - && x.Month == previousMonth - && x.Year == previousYear); - - if (previousArchiveRecord != null && previousArchiveRecord.PostCount > 0) { - previousArchiveRecord.PostCount--; - } - - // if previous count is now zero, delete the record - if (previousArchiveRecord != null && previousArchiveRecord.PostCount == 0) { - _blogArchiveRepository.Delete(previousArchiveRecord); - } - // increment new archive record var newArchiveRecord = _blogArchiveRepository .Table @@ -136,7 +134,31 @@ private void IncreaseBlogArchive(BlogPostPart blogPostPart) { _blogArchiveRepository.Create(newArchiveRecord); } - newArchiveRecord.PostCount++; + newArchiveRecord.PostCount++; + } + + private void ManageBlogArchiveSync(BlogPostPart blogPostPart) { + var commonPart = blogPostPart.As(); + if (commonPart == null || !commonPart.CreatedUtc.HasValue) + return; + + var timeZone = _workContextAccessor.GetContext().CurrentTimeZone; + var creationDate = TimeZoneInfo.ConvertTimeFromUtc(commonPart.CreatedUtc.Value, timeZone); + + if (blogPostPart.ArchiveSync == null) { + IncreaseBlogArchive(blogPostPart); + blogPostPart.ArchiveSync = creationDate; + } + else { + if (creationDate == blogPostPart.ArchiveSync) { + return; + } + else { + ReduceBlogArchiveByDate(blogPostPart.BlogPart.Id, blogPostPart.ArchiveSync); + IncreaseBlogArchive(blogPostPart); + blogPostPart.ArchiveSync = creationDate; + } + } } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPostPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPostPartHandler.cs index 5b3bcca0ce5..02fd498a298 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPostPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPostPartHandler.cs @@ -5,13 +5,18 @@ using Orchard.ContentManagement; using Orchard.ContentManagement.Handlers; using Orchard.Core.Common.Models; +using Orchard.Security; namespace Orchard.Blogs.Handlers { public class BlogPostPartHandler : ContentHandler { + private readonly IAuthorizationService _authorizationService; private readonly IBlogService _blogService; + private readonly IWorkContextAccessor _workContextAccessor; - public BlogPostPartHandler(IBlogService blogService, IBlogPostService blogPostService, RequestContext requestContext) { + public BlogPostPartHandler(IAuthorizationService authorizationService, IBlogService blogService, IBlogPostService blogPostService, RequestContext requestContext, IWorkContextAccessor workContextAccessor) { + _authorizationService = authorizationService; _blogService = blogService; + _workContextAccessor = workContextAccessor; OnGetDisplayShape(SetModelProperties); OnGetEditorShape(SetModelProperties); @@ -45,8 +50,29 @@ private static void SetModelProperties(BuildShapeContext context, BlogPostPart b protected override void GetItemMetadata(GetContentItemMetadataContext context) { var blogPost = context.ContentItem.As(); + if (blogPost == null) { + return; + } + + int blogId = 0; // BlogPart can be null if this is a new Blog Post item. - if (blogPost == null || blogPost.BlogPart == null) { + if (blogPost.BlogPart == null) { + var blogs = _blogService.Get().Where(x => _authorizationService.TryCheckAccess(Permissions.MetaListBlogs, _workContextAccessor.GetContext().CurrentUser, x)).ToArray(); + if (blogs.Count() == 1) { + var singleBlog = blogs.ElementAt(0); + if (singleBlog != null) blogId = singleBlog.Id; + } + } else { + blogId = blogPost.BlogPart.Id; + } + + if (blogId == 0) { + context.Metadata.CreateRouteValues = new RouteValueDictionary { + {"Area", "Orchard.Blogs"}, + {"Controller", "BlogPostAdmin"}, + {"Action", "CreateWithoutBlog"} + }; + return; } @@ -54,21 +80,21 @@ protected override void GetItemMetadata(GetContentItemMetadataContext context) { {"Area", "Orchard.Blogs"}, {"Controller", "BlogPostAdmin"}, {"Action", "Create"}, - {"blogId", blogPost.BlogPart.Id} + {"blogId", blogId} }; context.Metadata.EditorRouteValues = new RouteValueDictionary { {"Area", "Orchard.Blogs"}, {"Controller", "BlogPostAdmin"}, {"Action", "Edit"}, {"postId", context.ContentItem.Id}, - {"blogId", blogPost.BlogPart.Id} + {"blogId", blogId} }; context.Metadata.RemoveRouteValues = new RouteValueDictionary { {"Area", "Orchard.Blogs"}, {"Controller", "BlogPostAdmin"}, {"Action", "Delete"}, {"postId", context.ContentItem.Id}, - {"blogId", blogPost.BlogPart.Id} + {"blogId", blogId} }; } } diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Models/BlogPostPart.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Models/BlogPostPart.cs index 754e3e99d69..d495fb3a946 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Models/BlogPostPart.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Models/BlogPostPart.cs @@ -49,5 +49,10 @@ public bool HasPublished { public DateTime? PublishedUtc { get { return this.As().PublishedUtc; } } + + public DateTime? ArchiveSync { + get { return this.Retrieve(x => x.ArchiveSync); } + set { this.Store(x => x.ArchiveSync, value); } + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Module.txt b/src/Orchard.Web/Modules/Orchard.Blogs/Module.txt index 9032044e6a9..66c330cb7f1 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: The Orchard Blogs module is implementing basic blogging features. FeatureDescription: A simple web log. Dependencies: Shapes, Common, Feeds, Navigation, Orchard.Widgets, Orchard.Resources, Orchard.PublishLater, Orchard.Autoroute @@ -14,3 +14,8 @@ Features: Description: Blog easier using a dedicated MetaWeblogAPI-compatible publishing tool. Dependencies: XmlRpc, Orchard.Autoroute, Orchard.ContentPicker Category: Content Publishing + Orchard.Blogs.LocalizationExtensions: + Name: Blog multi-language support + Description: Extend Orchard Blogs module with fully integrated multi-language support. + Dependencies: Orchard.Localization + Category: Content diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj b/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj index d4b202396b3..292680e1959 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj @@ -12,8 +12,8 @@ Properties Orchard.Blogs Orchard.Blogs - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,9 @@ + + + true @@ -49,10 +52,12 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -65,34 +70,31 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll + + + @@ -151,10 +153,13 @@ + + + @@ -174,12 +179,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {475b6c45-b27c-438b-8966-908b9d6d1077} @@ -193,6 +198,10 @@ {f301ef7d-f19c-4d83-aa94-cb64f29c037d} Orchard.ContentPicker + + {fbc8b571-ed50-49d8-8d9d-64ab7454a0d6} + Orchard.Localization + {194d3ccc-1153-474d-8176-fde8d7d0d0bd} Orchard.Widgets @@ -234,7 +243,7 @@ - + 10.0 @@ -262,10 +271,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Properties/AssemblyInfo.cs index ca21df01aa5..b675d38d1a0 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Properties/AssemblyInfo.cs @@ -29,6 +29,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/ResourceManifest.cs b/src/Orchard.Web/Modules/Orchard.Blogs/ResourceManifest.cs index 73cec544281..46b2ab3c115 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/ResourceManifest.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/ResourceManifest.cs @@ -4,10 +4,14 @@ namespace Orchard.Blogs { public class ResourceManifest : IResourceManifestProvider { public void BuildManifests(ResourceManifestBuilder builder) { var manifest = builder.Add(); - manifest.DefineStyle("BlogsAdmin").SetUrl("orchard-blogs-admin.css"); - manifest.DefineStyle("BlogsArchives").SetUrl("orchard-blogs-archives.css"); + manifest.DefineStyle("BlogsAdmin") + .SetUrl("orchard-blogs-admin.min.css", "orchard-blogs-admin.css"); + manifest.DefineStyle("BlogsArchives") + .SetUrl("orchard-blogs-archives.min.css", "orchard-blogs-archives.css"); - manifest.DefineScript("BlogsArchives").SetUrl("orchard-blogs-archives.js").SetDependencies("jQuery"); + manifest.DefineScript("BlogsArchives") + .SetUrl("orchard-blogs-archives.min.js", "orchard-blogs-archives.js") + .SetDependencies("jQuery"); } } } diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Routes.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Routes.cs index 20219695e90..6fddb651240 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Routes.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Routes.cs @@ -17,12 +17,7 @@ public Routes( } public void GetRoutes(ICollection routes) { - foreach (var routeDescriptor in GetRoutes()) - routes.Add(routeDescriptor); - } - - public IEnumerable GetRoutes() { - return new[] { + var routeDescriptors = new[] { new RouteDescriptor { Route = new Route( "Admin/Blogs/Create", @@ -93,6 +88,20 @@ public IEnumerable GetRoutes() { }, new MvcRouteHandler()) }, + new RouteDescriptor { + Route = new Route( + "Admin/Blogs/Posts/CreateWithoutBlog", + new RouteValueDictionary { + {"area", "Orchard.Blogs"}, + {"controller", "BlogPostAdmin"}, + {"action", "CreateWithoutBlog"} + }, + new RouteValueDictionary (), + new RouteValueDictionary { + {"area", "Orchard.Blogs"} + }, + new MvcRouteHandler()) + }, new RouteDescriptor { Route = new Route( "Admin/Blogs/{blogId}/Posts/{postId}/Edit", @@ -211,6 +220,9 @@ public IEnumerable GetRoutes() { new MvcRouteHandler()) } }; + + foreach (var routeDescriptor in routeDescriptors) + routes.Add(routeDescriptor); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Scripts/orchard-blogs-archives.min.js b/src/Orchard.Web/Modules/Orchard.Blogs/Scripts/orchard-blogs-archives.min.js new file mode 100644 index 00000000000..f88f74ff1bf --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Scripts/orchard-blogs-archives.min.js @@ -0,0 +1 @@ +!function($){$((function(){$(".archives ul.years li.previous").each((function(){$(this).click((function(ev){ev&&!$(ev.target).not("a").size()||($(this).toggleClass("open"),$(this).find("h4>span").toggle(),$(this).children("ul").toggle())}))}))}))}(jQuery); \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogPostService.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogPostService.cs index b00ac51fd42..3ce165050a3 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogPostService.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogPostService.cs @@ -61,6 +61,18 @@ public int PostCount(BlogPart blogPart, VersionOptions versionOptions) { } public IEnumerable Get(BlogPart blogPart, ArchiveData archiveData) { + return GetBlogArchiveQuery(blogPart,archiveData) + .List().Select(ci => ci.As()); + } + + public IEnumerable Get(BlogPart blogPart, ArchiveData archiveData, int skip, int count) { + return GetBlogArchiveQuery(blogPart,archiveData) + .Slice(skip, count) + .ToList() + .Select(ci => ci.As()); + } + + private IContentQuery GetBlogArchiveQuery(BlogPart blogPart, ArchiveData archiveData) { var query = GetBlogQuery(blogPart, VersionOptions.Published); if (archiveData.Day > 0) { @@ -68,8 +80,7 @@ public IEnumerable Get(BlogPart blogPart, ArchiveData archiveData) query = query.Where(cr => cr.CreatedUtc >= dayDate && cr.CreatedUtc < dayDate.AddDays(1)); } - else if (archiveData.Month > 0) - { + else if (archiveData.Month > 0) { var monthDate = new DateTime(archiveData.Year, archiveData.Month, 1); query = query.Where(cr => cr.CreatedUtc >= monthDate && cr.CreatedUtc < monthDate.AddMonths(1)); @@ -79,8 +90,7 @@ public IEnumerable Get(BlogPart blogPart, ArchiveData archiveData) query = query.Where(cr => cr.CreatedUtc >= yearDate && cr.CreatedUtc < yearDate.AddYears(1)); } - - return query.List().Select(ci => ci.As()); + return query; } public IEnumerable> GetArchives(BlogPart blogPart) { diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogService.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogService.cs index b431dabca76..9ed5f9b1eac 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogService.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogService.cs @@ -51,8 +51,14 @@ public ContentItem Get(int id, VersionOptions versionOptions) { return blogPart == null ? null : blogPart.ContentItem; } + private IEnumerable _publishedBlogs; public IEnumerable Get() { - return Get(VersionOptions.Published); + // this is currently called at least twice per request on the + // back-office, both times by the code building the admin menu. + if (_publishedBlogs == null) { + _publishedBlogs = Get(VersionOptions.Published); + } + return _publishedBlogs; } public IEnumerable Get(VersionOptions versionOptions) { diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Services/IBlogPostService.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Services/IBlogPostService.cs index 427d41bb591..421077cbcfe 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Services/IBlogPostService.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Services/IBlogPostService.cs @@ -10,6 +10,7 @@ public interface IBlogPostService : IDependency { IEnumerable Get(BlogPart blogPart); IEnumerable Get(BlogPart blogPart, VersionOptions versionOptions); IEnumerable Get(BlogPart blogPart, ArchiveData archiveData); + IEnumerable Get(BlogPart blogPart, ArchiveData archiveData, int skip, int count); IEnumerable Get(BlogPart blogPart, int skip, int count); IEnumerable Get(BlogPart blogPart, int skip, int count, VersionOptions versionOptions); int PostCount(BlogPart blogPart); diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Services/XmlRpcHandler.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Services/XmlRpcHandler.cs index 99fdcf832dc..f2d49ab0cde 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Services/XmlRpcHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Services/XmlRpcHandler.cs @@ -18,6 +18,7 @@ using Orchard.Blogs.Extensions; using Orchard.Mvc.Html; using Orchard.Core.Title.Models; +using System.Linq; namespace Orchard.Blogs.Services { [OrchardFeature("Orchard.Blogs.RemotePublishing")] @@ -30,7 +31,7 @@ public class XmlRpcHandler : IXmlRpcHandler { private readonly RouteCollection _routeCollection; public XmlRpcHandler(IBlogService blogService, IBlogPostService blogPostService, IContentManager contentManager, - IAuthorizationService authorizationService, IMembershipService membershipService, + IAuthorizationService authorizationService, IMembershipService membershipService, RouteCollection routeCollection) { _blogService = blogService; _blogPostService = blogPostService; @@ -205,10 +206,10 @@ private int MetaWeblogNewPost( if (blogPost.Is()) { blogPost.As().Title = HttpUtility.HtmlDecode(title); } - + //AutoroutePart dynamic dBlogPost = blogPost; - if (dBlogPost.AutoroutePart!=null){ + if (dBlogPost.AutoroutePart!=null) { dBlogPost.AutoroutePart.DisplayAlias = slug; } @@ -340,11 +341,11 @@ private bool MetaWeblogDeletePost( } private IUser ValidateUser(string userName, string password) { - IUser user = _membershipService.ValidateUser(userName, password); - if (user == null) { - throw new OrchardCoreException(T("The username or e-mail or password provided is incorrect.")); + List validationErrors; + IUser user = _membershipService.ValidateUser(userName, password,out validationErrors); + if (validationErrors.Any()) { + throw new OrchardCoreException(validationErrors.FirstOrDefault()); } - return user; } @@ -361,13 +362,13 @@ private static XRpcStruct CreateBlogStruct( var blogStruct = new XRpcStruct() .Set("postid", blogPostPart.Id) .Set("title", HttpUtility.HtmlEncode(blogPostPart.Title)) - + .Set("description", blogPostPart.Text) .Set("link", url) .Set("permaLink", url); - + blogStruct.Set("wp_slug", blogPostPart.As().Path); - + if (blogPostPart.PublishedUtc != null) { blogStruct.Set("dateCreated", blogPostPart.PublishedUtc); diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Styles/orchard-blogs-admin.min.css b/src/Orchard.Web/Modules/Orchard.Blogs/Styles/orchard-blogs-admin.min.css new file mode 100644 index 00000000000..d88e1f4c5ac --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Styles/orchard-blogs-admin.min.css @@ -0,0 +1 @@ +#main .blog-description p{margin-bottom:1em} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Styles/orchard-blogs-archives.min.css b/src/Orchard.Web/Modules/Orchard.Blogs/Styles/orchard-blogs-archives.min.css new file mode 100644 index 00000000000..3eb325a8c1f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Styles/orchard-blogs-archives.min.css @@ -0,0 +1 @@ +.archives h3{margin-bottom:0}.archives ul{margin:0;padding:0}.archives ul .archives li{list-style-type:none}.archives ul.years li{list-style-type:none;margin:.6em 0 0}.archives ul.archiveMonthList li{margin:.2em 0}.archives ul.archiveMonthList li.first{margin-top:0}.archives ul.archiveMonthList li.last{margin-bottom:0}.archives ul.years li.previous h4 span{display:none}html.dyn .archives ul.years li.previous h4 span{display:inline}html.dyn .archives ul.years li h4,html.dyn .archives ul.years li ul{margin:.2em .2ex}html.dyn .archives ul.years li.previous h4:before{content:"⇓ "}html.dyn .archives ul.years li.previous{cursor:pointer;padding:.1em .2ex .2em 2ex;margin:0 -2ex}html.dyn .archives ul.years li.previous.hover{background-position:0 6px}html.dyn .archives ul.years li.previous.open h4:before{content:"⇑ "}html.dyn .archives ul.years li.previous.open.hover{background-position:0 6px}html.dyn .archives ul.years li.previous ul{display:none;margin-left:2ex} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/Item.cshtml b/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/Item.cshtml index 6534c6b2f79..76581b42c5f 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/Item.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/Item.cshtml @@ -1,5 +1,5 @@ @{ Layout.Title = T("Manage Blog").ToString(); } - @* Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type *@ - @Display(Model) +@* Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type *@ +@Display(Model) diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/List.cshtml b/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/List.cshtml index 4bed331b24f..8b0d61f72e2 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/List.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogAdmin/List.cshtml @@ -8,13 +8,13 @@ using(Html.BeginFormAntiForgeryPost(Url.Action("List", "Admin", new { area = "Contents", id = "" }))) {
    - @T(" | ") + - @Html.Hidden("returnUrl", ViewContext.RequestContext.HttpContext.Request.ToUrlString()) + @Html.Hidden("returnUrl", ViewContext.RequestContext.HttpContext.Request.RawUrl)
    diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogPost/ListByArchive.cshtml b/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogPost/ListByArchive.cshtml index 5d62ad77fa8..5a5a13a84ac 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogPost/ListByArchive.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Views/BlogPost/ListByArchive.cshtml @@ -15,4 +15,5 @@ @(new MvcHtmlString(Model.ArchiveData.Month > 0 ? string.Format(" / {0}", Html.Link(monthNames[Model.ArchiveData.Month - 1], Url.BlogArchiveMonth((BlogPart)Model.Blog, (int)Model.ArchiveData.Year, (int)Model.ArchiveData.Month))) : "")) @(new MvcHtmlString(Model.ArchiveData.Day > 0 ? string.Format(" / {0}", Html.Link((string)Model.ArchiveData.Day.ToString(), Url.BlogArchiveDay((BlogPart)Model.Blog, (int)Model.ArchiveData.Year, (int)Model.ArchiveData.Month, (int)Model.ArchiveData.Day))) : ""))
    -@Display(Model.ContentItems) \ No newline at end of file +@Display(Model.ContentItems) +@Display(Model.Pager) \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Views/Content-BlogPost.SummaryAdmin.cshtml b/src/Orchard.Web/Modules/Orchard.Blogs/Views/Content-BlogPost.SummaryAdmin.cshtml index 4fc4086fc5d..6ba4127d200 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Views/Content-BlogPost.SummaryAdmin.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Views/Content-BlogPost.SummaryAdmin.cshtml @@ -4,63 +4,78 @@ @{ Script.Require("ShapesBase"); ContentItem contentItem = Model.ContentItem; - var returnUrl = ViewContext.RequestContext.HttpContext.Request.ToUrlString(); + var returnUrl = ViewContext.RequestContext.HttpContext.Request.RawUrl; }
    +
    - +

    @Html.ItemAdminLink(contentItem)

    -
    @contentItem.TypeDefinition.DisplayName
    @if (Model.Header != null) { -
    @Display(Model.Header)
    +
    @Display(Model.Header)
    } @if (Model.Meta != null) { - + }
    + + @if (Model.Content != null) { -
    @Display(Model.Content)
    +
    @Display(Model.Content)
    }
    \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Views/Parts.Blogs.Blog.SummaryAdmin.cshtml b/src/Orchard.Web/Modules/Orchard.Blogs/Views/Parts.Blogs.Blog.SummaryAdmin.cshtml index 4cc403277c4..2218d0b7fec 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Views/Parts.Blogs.Blog.SummaryAdmin.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Views/Parts.Blogs.Blog.SummaryAdmin.cshtml @@ -1,10 +1,15 @@ @using Orchard.Blogs.Extensions; @using Orchard.Blogs.Models; @using Orchard.ContentManagement; -@using Orchard.Utility.Extensions; @{ ContentItem contentItem = Model.ContentItem; BlogPart blog = (BlogPart)contentItem.Get(typeof(BlogPart)); } -@T("List Posts")@T(" | ") -@T("New Post")@T(" | ") \ No newline at end of file + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Views/Parts.Blogs.BlogPost.ListAdmin.cshtml b/src/Orchard.Web/Modules/Orchard.Blogs/Views/Parts.Blogs.BlogPost.ListAdmin.cshtml index 7cd61b4a808..6170489da5b 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Views/Parts.Blogs.BlogPost.ListAdmin.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Views/Parts.Blogs.BlogPost.ListAdmin.cshtml @@ -1,17 +1,17 @@ @using Orchard.Core.Contents.ViewModels; -@using Orchard.Utility.Extensions; + @if (Model.ContentItems.Items.Count > 0) { using (Html.BeginFormAntiForgeryPost(Url.Action("List", "Admin", new { area = "Contents", id = "" }))) {
    - @T(" | ") + - @Html.Hidden("returnUrl", ViewContext.RequestContext.HttpContext.Request.ToUrlString()) + @Html.Hidden("returnUrl", ViewContext.RequestContext.HttpContext.Request.RawUrl)
    diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Web.config b/src/Orchard.Web/Modules/Orchard.Blogs/Web.config index a3cb5df907e..baf3b31252b 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Web.config @@ -7,7 +7,7 @@ - + @@ -21,39 +21,58 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/packages.config b/src/Orchard.Web/Modules/Orchard.Blogs/packages.config index 6729ced4977..1c55d6960bb 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Blogs/packages.config @@ -1,7 +1,8 @@  - - - - - \ No newline at end of file + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Module.txt b/src/Orchard.Web/Modules/Orchard.Caching/Module.txt index de0050dcbdb..4fb6f51f482 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Caching/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: Sébastien Ros Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Provides an API to cache business data. Features: Orchard.Caching: diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Orchard.Caching.csproj b/src/Orchard.Web/Modules/Orchard.Caching/Orchard.Caching.csproj index 5ce025dc4e1..5ba73e1ecc2 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Orchard.Caching.csproj +++ b/src/Orchard.Web/Modules/Orchard.Caching/Orchard.Caching.csproj @@ -12,8 +12,8 @@ Properties Orchard.Caching Orchard.Caching - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -25,6 +25,7 @@ + true @@ -50,7 +51,6 @@ ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -62,29 +62,23 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -97,7 +91,7 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) @@ -108,7 +102,7 @@ - + 10.0 @@ -134,7 +128,7 @@ --> - + @@ -148,10 +142,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Caching/Properties/AssemblyInfo.cs index 86bf76f8bfa..f2b7189a938 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Caching/Properties/AssemblyInfo.cs @@ -31,6 +31,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Caching/Web.config b/src/Orchard.Web/Modules/Orchard.Caching/Web.config index 314606a772b..1fc8f61a052 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Caching/Web.config @@ -7,7 +7,7 @@ - + @@ -22,36 +22,47 @@ - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Caching/packages.config b/src/Orchard.Web/Modules/Orchard.Caching/packages.config index 6729ced4977..84f4c1e1392 100644 --- a/src/Orchard.Web/Modules/Orchard.Caching/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Caching/packages.config @@ -1,7 +1,7 @@  - - - - - \ No newline at end of file + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleAssemblyInfo.txt b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleAssemblyInfo.txt index e493ab9bd95..bafec8967bf 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleAssemblyInfo.txt +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleAssemblyInfo.txt @@ -32,6 +32,6 @@ using System.Security; // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleCsProj.txt b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleCsProj.txt index e26dd842d60..03151f59d42 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleCsProj.txt +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleCsProj.txt @@ -12,8 +12,8 @@ Properties $$ModuleName$$ $$ModuleName$$ - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -47,26 +47,50 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + True + + + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + True + - 3.5 + - - False - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll + True + + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll + True + + + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll + True + + + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll + True + + + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll + True + + + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll + True - - - - $$CompileIncludes$$ @@ -81,24 +105,8 @@ - - - - $(ProjectDir)\..\Manifests - - - - - - + + @@ -112,10 +120,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleManifest.txt b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleManifest.txt index 5185d6ef803..6cb3ee819c1 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleManifest.txt +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleManifest.txt @@ -1,9 +1,9 @@ Name: $$ModuleName$$ AntiForgery: enabled Author: The Orchard Team -Website: http://orchardproject.net +Website: https://orchardproject.net Version: 1.0 -OrchardVersion: 1.0 +OrchardVersion: 1.10.3 Description: Description for the module Features: $$ModuleName$$: diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModulePackagesConfig.txt b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModulePackagesConfig.txt new file mode 100644 index 00000000000..1c55d6960bb --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModulePackagesConfig.txt @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleRootWebConfig.txt b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleRootWebConfig.txt index 9c722b6debd..48c8a203121 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleRootWebConfig.txt +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleRootWebConfig.txt @@ -7,7 +7,7 @@ - + @@ -21,25 +21,25 @@ - + + + + + + + + - + - + - - + + @@ -47,15 +47,15 @@ - + - - + + - - + + diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleTestsCsProj.txt b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleTestsCsProj.txt index cc692b1c72c..88abe3e8280 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleTestsCsProj.txt +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleTestsCsProj.txt @@ -9,7 +9,8 @@ Properties $$ProjectName$$ $$ProjectName$$ - v4.5.2 + v4.8 + 7.3 4.0 @@ -37,11 +38,11 @@ ..\..\..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll - - ..\..\..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll + + ..\..\..\..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll - - ..\..\..\..\packages\NHibernate.4.0.1.4000\lib\net40\NHibernate.dll + + ..\..\..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll ..\..\..\..\packages\NUnit.2.5.10.11092\lib\nunit.framework.dll @@ -68,4 +69,4 @@ $$OrchardReferences$$ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ThemeManifest.txt b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ThemeManifest.txt index 35f48d02531..5a303397596 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ThemeManifest.txt +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ThemeManifest.txt @@ -1,6 +1,6 @@ Name: $$ThemeName$$ Author: The Orchard Team -Website: http://www.orchardproject.net +Website: https://www.orchardproject.net Description: Description for the theme Version: 1.0 BaseTheme: $$BaseTheme$$ diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/Commands/CodeGenerationCommands.cs b/src/Orchard.Web/Modules/Orchard.CodeGeneration/Commands/CodeGenerationCommands.cs index 5f5501776ea..0e22fc60416 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/Commands/CodeGenerationCommands.cs +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/Commands/CodeGenerationCommands.cs @@ -291,6 +291,8 @@ private void CreateFilesFromTemplates(string moduleName, string projectGuid) { File.WriteAllText(modulePath + "Styles\\Styles.min.css", File.ReadAllText(_codeGenTemplatePath + "ModuleStylesMinCss.txt")); content.Add(modulePath + "Styles\\Styles.min.css"); + File.WriteAllText(modulePath + "packages.config", File.ReadAllText(_codeGenTemplatePath + "ModulePackagesConfig.txt")); + content.Add(modulePath + "packages.config"); File.WriteAllText(modulePath + "Web.config", File.ReadAllText(_codeGenTemplatePath + "ModuleRootWebConfig.txt")); content.Add(modulePath + "Web.config"); File.WriteAllText(modulePath + "Scripts\\Web.config", File.ReadAllText(_codeGenTemplatePath + "StaticFilesWebConfig.txt")); @@ -330,22 +332,22 @@ private static string GetOrchardReferences() { @" {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) " : @" False ..\..\bin\Orchard.Core.dll - false + $(MvcBuildViews) False ..\..\bin\Orchard.Framework.dll - false + $(MvcBuildViews) "; } @@ -404,6 +406,9 @@ private void CreateThemeFromTemplates(TextWriter output, string themeName, strin // create new csproj for the theme if (projectGuid != null) { + File.WriteAllText(themePath + "packages.config", File.ReadAllText(_codeGenTemplatePath + "ModulePackagesConfig.txt")); + createdFiles.Add(themePath + "packages.config"); + var itemGroup = CreateProjectItemGroup(themePath, createdFiles, createdFolders); string projectText = CreateCsProject(themeName, projectGuid, itemGroup, null); File.WriteAllText(themePath + "\\" + themeName + ".csproj", projectText); @@ -431,21 +436,34 @@ private void AddToSolution(TextWriter output, string projectName, string project var projectReference = string.Format("EndProject\r\nProject(\"{{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}}\") = \"{0}\", \"Orchard.Web\\{2}\\{0}\\{0}.csproj\", \"{{{1}}}\"\r\n", projectName, projectGuid, containingFolder); var projectConfiguationPlatforms = string.Format("\t{{{0}}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{{{0}}}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{{{0}}}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{{{0}}}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t", projectGuid); var solutionText = File.ReadAllText(solutionPath); + solutionText = NormalizeLineEndings(solutionText); solutionText = solutionText.Insert(solutionText.LastIndexOf("EndProject\r\n"), projectReference); + solutionText = AppendProjectSection(solutionText, "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Orchard.Web\"", "ProjectDependencies", string.Format("\t{{{0}}} = {{{0}}}\r\n\t", projectGuid)); solutionText = AppendGlobalSection(solutionText, "ProjectConfigurationPlatforms", projectConfiguationPlatforms); - solutionText = AppendGlobalSection(solutionText, "NestedProjects", "\t{" + projectGuid + "} = {" + solutionFolderGuid + "}\r\n\t"); + solutionText = AppendGlobalSection(solutionText, "NestedProjects", string.Format("\t{{{0}}} = {{{1}}}\r\n\t", projectGuid, solutionFolderGuid)); File.WriteAllText(solutionPath, solutionText); TouchSolution(output); } } } + private string NormalizeLineEndings(string input) { + return input.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", "\r\n"); + } + private string AppendGlobalSection(string solutionText, string sectionName, string content) { var sectionStart = solutionText.IndexOf(string.Format("GlobalSection({0})", sectionName)); var sectionEnd = solutionText.IndexOf("EndGlobalSection", sectionStart); return solutionText.Insert(sectionEnd, content); } + private string AppendProjectSection(string solutionText, string projectNode, string sectionName, string content) { + var projectStart = solutionText.IndexOf(projectNode); + var sectionStart = solutionText.IndexOf(string.Format("ProjectSection({0})", sectionName), projectStart); + var sectionEnd = solutionText.IndexOf("EndProjectSection", sectionStart); + return solutionText.Insert(sectionEnd, content); + } + private static string CreateProjectItemGroup(string relativeFromPath, HashSet content, HashSet folders) { var contentInclude = ""; if (relativeFromPath != null && !relativeFromPath.EndsWith("\\", StringComparison.OrdinalIgnoreCase)) { diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/Module.txt b/src/Orchard.Web/Modules/Orchard.CodeGeneration/Module.txt index 864e6d3f786..49f1e87e4bf 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Tools to create Orchard components. FeatureDescription: Tools to create Orchard components. Category: Developer diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/Orchard.CodeGeneration.csproj b/src/Orchard.Web/Modules/Orchard.CodeGeneration/Orchard.CodeGeneration.csproj index e7c8b07d83d..05eb8c41bd3 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/Orchard.CodeGeneration.csproj +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/Orchard.CodeGeneration.csproj @@ -13,8 +13,8 @@ Properties Orchard.CodeGeneration Orchard.CodeGeneration - v4.5.2 - false + v4.8 + 7.3 false @@ -27,6 +27,7 @@ + true @@ -52,7 +53,6 @@ ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -63,28 +63,22 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -101,14 +95,18 @@ - + + + + + Designer @@ -117,25 +115,16 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) - - - - - - - - - - + 10.0 @@ -163,10 +152,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.CodeGeneration/Properties/AssemblyInfo.cs index f6a7886d7aa..0195a9612bd 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/Web.config b/src/Orchard.Web/Modules/Orchard.CodeGeneration/Web.config index 314606a772b..1fc8f61a052 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/Web.config +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/Web.config @@ -7,7 +7,7 @@ - + @@ -22,36 +22,47 @@ - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/packages.config b/src/Orchard.Web/Modules/Orchard.CodeGeneration/packages.config index 6729ced4977..84f4c1e1392 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/packages.config +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/packages.config @@ -1,7 +1,7 @@  - - - - - \ No newline at end of file + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Controllers/CommentController.cs b/src/Orchard.Web/Modules/Orchard.Comments/Controllers/CommentController.cs index 5def988b9b7..1a9d637621d 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Controllers/CommentController.cs +++ b/src/Orchard.Web/Modules/Orchard.Comments/Controllers/CommentController.cs @@ -37,7 +37,7 @@ public ActionResult Create(string returnUrl) { Services.Notifier.Error(T("Email is invalid or is longer than 255 chars")); } - if (!ModelState.IsValidField("Comments.Site")) { + if (!ModelState.IsValidField("Comments.SiteName")) { Services.Notifier.Error(T("Site url is invalid or is longer than 255 chars")); } diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Drivers/CommentsContainerPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Comments/Drivers/CommentsContainerPartDriver.cs index 9c067a9ecb8..85a1c375938 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Drivers/CommentsContainerPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Comments/Drivers/CommentsContainerPartDriver.cs @@ -13,7 +13,7 @@ public CommentsContainerPartDriver(ICommentService commentService) { protected override DriverResult Display(CommentsContainerPart part, string displayType, dynamic shapeHelper) { - var commentsForCommentedContent = _commentService.GetCommentsForCommentedContent(part.ContentItem.Id); + var commentsForCommentedContent = _commentService.GetCommentsForContainer(part.ContentItem.Id); Func pendingCount = () => commentsForCommentedContent.Where(x => x.Status == CommentStatus.Pending).Count(); Func approvedCount = () => commentsForCommentedContent.Where(x => x.Status == CommentStatus.Approved).Count(); diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Drivers/CommentsPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Comments/Drivers/CommentsPartDriver.cs index a59a5fb7aea..78593665352 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Drivers/CommentsPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Comments/Drivers/CommentsPartDriver.cs @@ -70,14 +70,10 @@ protected override DriverResult Display(CommentsPart part, string displayType, d return shapeHelper.Parts_CommentForm(EditorShape: editorShape, CanStillComment: _commentService.CanStillCommentOn(part)); }), - ContentShape("Parts_Comments_Count", - () => { - if (part.CommentsShown == false) - return null; - - return shapeHelper.Parts_Comments_Count( - CommentCount: part.CommentsCount); - }), + ContentShape("Parts_Comments_Count", () => + part.CommentsShown ? shapeHelper.Parts_Comments_Count(CommentCount: part.CommentsCount) : null), + ContentShape("Parts_Comments_Count_Summary", () => + part.CommentsShown ? shapeHelper.Parts_Comments_Count_Summary(CommentCount: part.CommentsCount) : null), ContentShape("Parts_Comments_Count_SummaryAdmin", () => { diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Module.txt b/src/Orchard.Web/Modules/Orchard.Comments/Module.txt index 342ebd97b65..fbe839a23a2 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Comments/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: The comments system implemented by this module can be applied to arbitrary Orchard content types, such as blogs and pages. It includes comment validation and spam protection through the Akismet service. Features: Orchard.Comments: diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Orchard.Comments.csproj b/src/Orchard.Web/Modules/Orchard.Comments/Orchard.Comments.csproj index 900a002ab69..581d2370355 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Orchard.Comments.csproj +++ b/src/Orchard.Web/Modules/Orchard.Comments/Orchard.Comments.csproj @@ -12,8 +12,8 @@ Properties Orchard.Comments Orchard.Comments - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,9 @@ + + + true @@ -49,10 +52,12 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -65,28 +70,22 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -148,12 +147,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {6f759635-13d7-4e94-bcc9-80445d63f117} @@ -212,7 +211,7 @@ - + @@ -222,6 +221,9 @@ + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) @@ -246,7 +248,7 @@ --> - + @@ -260,10 +262,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Placement.info b/src/Orchard.Web/Modules/Orchard.Comments/Placement.info index bb34a79bd8e..a741de64f94 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Placement.info +++ b/src/Orchard.Web/Modules/Orchard.Comments/Placement.info @@ -3,6 +3,7 @@ @@ -13,21 +14,31 @@ + - + - - - - + + + + + + + + - - + + + - + diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Comments/Properties/AssemblyInfo.cs index 7f7fbd8d0f0..8e818a49c7e 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Comments/Properties/AssemblyInfo.cs @@ -30,5 +30,5 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Services/CommentService.cs b/src/Orchard.Web/Modules/Orchard.Comments/Services/CommentService.cs index 02dd576f1c5..f61d1082839 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Services/CommentService.cs +++ b/src/Orchard.Web/Modules/Orchard.Comments/Services/CommentService.cs @@ -60,6 +60,11 @@ IMessageService messageService public Localizer T { get; set; } public ILogger Logger { get; set; } + public IContentQuery GetCommentsForContainer(int id) { + return GetComments() + .Where(c => c.CommentedOnContainer == id); + } + public CommentPart GetComment(int id) { return _orchardServices.ContentManager.Get(id); } diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Services/ICommentService.cs b/src/Orchard.Web/Modules/Orchard.Comments/Services/ICommentService.cs index 30abd715c54..dd96940ca37 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Services/ICommentService.cs +++ b/src/Orchard.Web/Modules/Orchard.Comments/Services/ICommentService.cs @@ -8,6 +8,7 @@ public interface ICommentService : IDependency { IContentQuery GetComments(CommentStatus status); IContentQuery GetCommentsForCommentedContent(int id); IContentQuery GetCommentsForCommentedContent(int id, CommentStatus status); + IContentQuery GetCommentsForContainer(int id); CommentPart GetComment(int id); ContentItemMetadata GetDisplayForCommentedContent(int id); ContentItem GetCommentedContent(int id); diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Shapes.cs b/src/Orchard.Web/Modules/Orchard.Comments/Shapes.cs index 38564917cca..4a4b3774736 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Shapes.cs +++ b/src/Orchard.Web/Modules/Orchard.Comments/Shapes.cs @@ -34,7 +34,7 @@ public void CommentSummaryLinks(dynamic Display, TextWriter Output, HtmlHelper H Area = "Orchard.Comments", Controller = "Admin", id = item.Id, - returnUrl = Html.ViewContext.HttpContext.Request.ToUrlString() + returnUrl = Html.ViewContext.HttpContext.Request.RawUrl }); } diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Comments/Views/Admin/Index.cshtml index b6e856213b4..a5042c23c39 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Comments/Views/Admin/Index.cshtml @@ -11,13 +11,13 @@ Layout.Title = T("Comments").ToString(); } -@using(Html.BeginFormAntiForgeryPost()) { +@using (Html.BeginFormAntiForgeryPost()) { @Html.ValidationSummary()
    @@ -44,7 +44,7 @@ - + @T("Status") @T("Author") @T("Comment") @@ -58,47 +58,56 @@ if (!HasText(commentEntry.Comment.UserName)) { commentClass = "anonymous"; } - - - - - - - @if (commentEntry.Comment.Status == CommentStatus.Pending) { @T("Pending") } - else { @T("Approved") } - - -
    @commentEntry.Comment.Author
    - @if (HasText(commentEntry.Comment.UserName) && commentEntry.Comment.Author != commentEntry.Comment.UserName) { -
    @commentEntry.Comment.UserName
    - } - - -

    - @if (commentEntry.Comment.CommentText != null) { + + + + + + + @if (commentEntry.Comment.Status == CommentStatus.Pending) { @T("Pending") } + else { @T("Approved") } + + +
    @commentEntry.Comment.Author
    + @if (HasText(commentEntry.Comment.UserName) && commentEntry.Comment.Author != commentEntry.Comment.UserName) { +
    @commentEntry.Comment.UserName
    + } + + +

    + @if (commentEntry.Comment.CommentText != null) { var ellipsized = Html.Ellipsize(commentEntry.Comment.CommentText, 500); var paragraphed = new HtmlString(ellipsized.ToHtmlString().Replace("\r\n", "

    ")); -

    @paragraphed

    - } - else { - @T("[Empty]") - } - - @Html.ItemDisplayLink(commentEntry.CommentedOn) - -
    - @if (commentEntry.Comment.Status != CommentStatus.Approved) { - @T("Approve")@T(" | ") +

    @paragraphed

    } else { - @T("Unapprove")@T(" | ") + @T("[Empty]") } - @T("Edit")@T(" | ") - @T("Delete") -
    - - commentIndex = commentIndex + 1; - } + + @Html.ItemDisplayLink(commentEntry.CommentedOn) + + + + + commentIndex = commentIndex + 1; + } @Display(Model.Pager)
    diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.Comment.SummaryAdmin.cshtml b/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.Comment.SummaryAdmin.cshtml index 43060eb4720..b52572a424b 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.Comment.SummaryAdmin.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.Comment.SummaryAdmin.cshtml @@ -1,19 +1,22 @@ -@using Orchard.Comments.Models; +@using Orchard.Comments.Models @using Orchard.ContentManagement -@using Orchard.Utility.Extensions @{ CommentPart comment = Model.ContentPart; var settings = WorkContext.CurrentSite.As(); } -@if(settings.ModerateComments) { - - if (comment.Status != CommentStatus.Pending) { - @Html.Link(@T("Approve").Text, Url.Action("Approve", "Admin", new {area = "Orchard.Comments", comment.Id, returnUrl = Request.ToUrlString()}), new {itemprop = "UnsafeUrl"}) - } - else { - @Html.Link(@T("Unapprove").Text, Url.Action("Unapprove", "Admin", new {area = "Orchard.Comments", comment.Id, returnUrl = Request.ToUrlString()}), new {itemprop = "UnsafeUrl"}) - } - @T(" | ") +@if (settings.ModerateComments) { + } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.CommentForm.cshtml b/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.CommentForm.cshtml index 312ecf49eda..5d480bd9633 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.CommentForm.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.CommentForm.cshtml @@ -33,7 +33,7 @@ else if (isAuthorized) {
    } @Html.ValidationSummary() - using (Html.BeginFormAntiForgeryPost(Url.Action("Create", "Comment", new { Area = "Orchard.Comments", ReturnUrl = Context.Request.ToUrlString() }), FormMethod.Post, new { @class = "comment-form", data_contentitem_id = commentsPart.ContentItem.Id })) { + using (Html.BeginFormAntiForgeryPost(Url.Action("Create", "Comment", new { Area = "Orchard.Comments", ReturnUrl = Context.Request.RawUrl }), FormMethod.Post, new { @class = "comment-form", data_contentitem_id = commentsPart.ContentItem.Id })) { if (TempData.ContainsKey("Comments.InvalidCommentEditorShape")) { @Display(TempData["Comments.InvalidCommentEditorShape"]); } @@ -41,6 +41,5 @@ else if (isAuthorized) { @Display(Model.EditorShape) } - } - + } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.Comments.Count.Summary.cshtml b/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.Comments.Count.Summary.cshtml new file mode 100644 index 00000000000..e4f308181af --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.Comments.Count.Summary.cshtml @@ -0,0 +1 @@ +@T.Plural("No Comments", "1 Comment", "{0} Comments", (int)Model.CommentCount) \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.Comments.Count.cshtml b/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.Comments.Count.cshtml index e4f308181af..2d8a2bd9af3 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.Comments.Count.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.Comments.Count.cshtml @@ -1 +1 @@ -@T.Plural("No Comments", "1 Comment", "{0} Comments", (int)Model.CommentCount) \ No newline at end of file +

    @T.Plural("No Comments", "1 Comment", "{0} Comments", (int)Model.CommentCount)

    \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.ListOfComments.cshtml b/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.ListOfComments.cshtml index 6830a5a6b11..cf5288e3b15 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.ListOfComments.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Comments/Views/Parts.ListOfComments.cshtml @@ -7,7 +7,6 @@ Model.List.Id = string.Format("comments_{0}", commentsPart.ContentItem.Id); } -

    @T.Plural("No Comments", "1 Comment", "{0} Comments", (int)Model.CommentCount)

    @Display(Model.List) @* render reply button if threaded comments enabled *@ diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Web.config b/src/Orchard.Web/Modules/Orchard.Comments/Web.config index f7746e57627..c4ebc5c2771 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Comments/Web.config @@ -7,7 +7,7 @@ - + @@ -21,39 +21,58 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Comments/packages.config b/src/Orchard.Web/Modules/Orchard.Comments/packages.config index 6729ced4977..1c55d6960bb 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Comments/packages.config @@ -1,7 +1,8 @@  - - - - - \ No newline at end of file + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Conditions/Module.txt b/src/Orchard.Web/Modules/Orchard.Conditions/Module.txt index 0257f3f43c8..efadc97f6c2 100644 --- a/src/Orchard.Web/Modules/Orchard.Conditions/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Conditions/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Provides a rules API that evaluate to true or false. Features: Orchard.Conditions: diff --git a/src/Orchard.Web/Modules/Orchard.Conditions/Orchard.Conditions.csproj b/src/Orchard.Web/Modules/Orchard.Conditions/Orchard.Conditions.csproj index cdf31e39ac4..12f420c38a2 100644 --- a/src/Orchard.Web/Modules/Orchard.Conditions/Orchard.Conditions.csproj +++ b/src/Orchard.Web/Modules/Orchard.Conditions/Orchard.Conditions.csproj @@ -12,8 +12,8 @@ Properties Orchard.Conditions Orchard.Conditions - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -25,6 +25,7 @@ +
    true @@ -51,7 +52,6 @@ ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -63,29 +63,23 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -100,12 +94,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {99002b65-86f7-415e-bf4a-381aa8ab9ccc} @@ -122,7 +116,7 @@
    - + 10.0 @@ -148,7 +142,7 @@ --> - + @@ -162,10 +156,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Conditions/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Conditions/Properties/AssemblyInfo.cs index 2bd36dba7bc..2479cb057e8 100644 --- a/src/Orchard.Web/Modules/Orchard.Conditions/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Conditions/Properties/AssemblyInfo.cs @@ -32,6 +32,6 @@ // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Conditions/Providers/UrlCondition.cs b/src/Orchard.Web/Modules/Orchard.Conditions/Providers/UrlCondition.cs index 5a7e0b9d209..e09c0d5cc76 100644 --- a/src/Orchard.Web/Modules/Orchard.Conditions/Providers/UrlCondition.cs +++ b/src/Orchard.Web/Modules/Orchard.Conditions/Providers/UrlCondition.cs @@ -14,33 +14,39 @@ public UrlCondition(IHttpContextAccessor httpContextAccessor, ShellSettings shel } public void Evaluate(ConditionEvaluationContext evaluationContext) { - if (!String.Equals(evaluationContext.FunctionName, "url", StringComparison.OrdinalIgnoreCase)) + if (!string.Equals(evaluationContext.FunctionName, "url", StringComparison.OrdinalIgnoreCase)) return; var context = _httpContextAccessor.Current(); - var url = Convert.ToString(evaluationContext.Arguments[0]); - if (url.StartsWith("~/")) { - url = url.Substring(2); - var appPath = context.Request.ApplicationPath; - if (appPath == "/") - appPath = ""; - - if(!String.IsNullOrEmpty(_shellSettings.RequestUrlPrefix)) - appPath = String.Concat(appPath, "/", _shellSettings.RequestUrlPrefix); - - url = String.Concat(appPath, "/", url); + foreach (var argument in evaluationContext.Arguments) { + var url = Convert.ToString(argument); + if (url.StartsWith("~/")) { + url = url.Substring(2); + var appPath = context.Request.ApplicationPath; + if (appPath == "/") + appPath = ""; + + if (!string.IsNullOrEmpty(_shellSettings.RequestUrlPrefix)) + appPath = string.Concat(appPath, "/", _shellSettings.RequestUrlPrefix); + + url = string.Concat(appPath, "/", url); + } + + if (!url.Contains("?")) + url = url.TrimEnd('/'); + + var requestPath = context.Request.Path; + if (!requestPath.Contains("?")) + requestPath = requestPath.TrimEnd('/'); + + if ((url.EndsWith("*") && requestPath.StartsWith(url.TrimEnd('*'), StringComparison.OrdinalIgnoreCase)) || + string.Equals(requestPath, url, StringComparison.OrdinalIgnoreCase)) { + evaluationContext.Result = true; + return; + } } - if (!url.Contains("?")) - url = url.TrimEnd('/'); - - var requestPath = context.Request.Path; - if (!requestPath.Contains("?")) - requestPath = requestPath.TrimEnd('/'); - - evaluationContext.Result = url.EndsWith("*") - ? requestPath.StartsWith(url.TrimEnd('*'), StringComparison.OrdinalIgnoreCase) - : string.Equals(requestPath, url, StringComparison.OrdinalIgnoreCase); + evaluationContext.Result = false; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Conditions/Web.config b/src/Orchard.Web/Modules/Orchard.Conditions/Web.config index 104465f24fd..b4b1cf0de0f 100644 --- a/src/Orchard.Web/Modules/Orchard.Conditions/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Conditions/Web.config @@ -7,7 +7,7 @@ - + @@ -22,13 +22,13 @@ - + - + @@ -36,24 +36,36 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Conditions/packages.config b/src/Orchard.Web/Modules/Orchard.Conditions/packages.config index 6729ced4977..84f4c1e1392 100644 --- a/src/Orchard.Web/Modules/Orchard.Conditions/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Conditions/packages.config @@ -1,7 +1,7 @@  - - - - - \ No newline at end of file + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.ContentPermissions/Module.txt b/src/Orchard.Web/Modules/Orchard.ContentPermissions/Module.txt index e5c0d08b2f3..68770e5bec1 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPermissions/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.ContentPermissions/Module.txt @@ -2,8 +2,8 @@ Name: Orchard.ContentPermissions AntiForgery: enabled Author: Chris Pyle, Sbastien Ros Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Allows item-level front end view permissions. Features: Orchard.ContentPermissions: diff --git a/src/Orchard.Web/Modules/Orchard.ContentPermissions/Orchard.ContentPermissions.csproj b/src/Orchard.Web/Modules/Orchard.ContentPermissions/Orchard.ContentPermissions.csproj index 77154566ebe..c5be1a55df1 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPermissions/Orchard.ContentPermissions.csproj +++ b/src/Orchard.Web/Modules/Orchard.ContentPermissions/Orchard.ContentPermissions.csproj @@ -12,8 +12,8 @@ Properties Orchard.ContentPermissions Orchard.ContentPermissions - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,9 @@ + + + true @@ -49,10 +52,12 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -67,29 +72,23 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -107,12 +106,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {D10AD48F-407D-4DB5-A328-173EC7CB010F} @@ -154,7 +153,7 @@ - + 10.0 @@ -180,7 +179,7 @@ --> - + @@ -194,10 +193,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.ContentPermissions/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.ContentPermissions/Properties/AssemblyInfo.cs index e3900b10757..ccba611d82a 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPermissions/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPermissions/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.ContentPermissions/Web.config b/src/Orchard.Web/Modules/Orchard.ContentPermissions/Web.config index a3cb5df907e..baf3b31252b 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPermissions/Web.config +++ b/src/Orchard.Web/Modules/Orchard.ContentPermissions/Web.config @@ -7,7 +7,7 @@ - + @@ -21,39 +21,58 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.ContentPermissions/packages.config b/src/Orchard.Web/Modules/Orchard.ContentPermissions/packages.config index 6729ced4977..1c55d6960bb 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPermissions/packages.config +++ b/src/Orchard.Web/Modules/Orchard.ContentPermissions/packages.config @@ -1,7 +1,8 @@  - - - - - \ No newline at end of file + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Controllers/AdminController.cs index 26e02fe50ae..7f7eb3e0db6 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Controllers/AdminController.cs @@ -160,6 +160,7 @@ public ActionResult Index(ListContentsViewModel model, PagerParameters pagerPara RouteData.Values["Options.SelectedFilter"] = model.Options.SelectedFilter; RouteData.Values["Options.OrderBy"] = model.Options.OrderBy.ToString(); RouteData.Values["Options.ContentsStatus"] = model.Options.ContentsStatus.ToString(); + RouteData.Values["Options.SelectedCulture"] = model.Options.SelectedCulture; return new ShapeResult(this, Services.New.ContentPicker().Tab(tab)); } diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentMenuItemPartDriver.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentMenuItemPartDriver.cs index 6deda116ae2..3ce50ed99be 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentMenuItemPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentMenuItemPartDriver.cs @@ -41,7 +41,9 @@ protected override DriverResult Editor(ContentMenuItemPart part, dynamic shapeHe protected override DriverResult Editor(ContentMenuItemPart part, IUpdateModel updater, dynamic shapeHelper) { var currentUser = _workContextAccessor.GetContext().CurrentUser; - if (!_authorizationService.TryCheckAccess(Permissions.ManageMenus, currentUser, part)) + var menu = ((dynamic)part.ContentItem).MenuPart.Menu; + + if (!_authorizationService.TryCheckAccess(Permissions.ManageMenus, currentUser, menu)) return null; var model = new ContentMenuItemEditViewModel(); diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentPickerFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentPickerFieldDriver.cs index 394d117295c..85609bef513 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentPickerFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentPickerFieldDriver.cs @@ -8,13 +8,19 @@ using Orchard.Localization; using Orchard.Utility.Extensions; using Orchard.ContentPicker.Fields; +using Orchard.Tokens; +using System.Collections.Generic; namespace Orchard.ContentPicker.Drivers { public class ContentPickerFieldDriver : ContentFieldDriver { private readonly IContentManager _contentManager; + private readonly ITokenizer _tokenizer; - public ContentPickerFieldDriver(IContentManager contentManager) { + public ContentPickerFieldDriver( + IContentManager contentManager, + ITokenizer tokenizer) { _contentManager = contentManager; + _tokenizer = tokenizer; T = NullLocalizer.Instance; } @@ -42,18 +48,38 @@ protected override DriverResult Display(ContentPart part, Fields.ContentPickerFi protected override DriverResult Editor(ContentPart part, Fields.ContentPickerField field, dynamic shapeHelper) { return ContentShape("Fields_ContentPicker_Edit", GetDifferentiator(field, part), () => { + var ids = part.IsNew() + ? GetDefaultids(part, field) + : field.Ids; var model = new ContentPickerFieldViewModel { Field = field, Part = part, - ContentItems = _contentManager.GetMany(field.Ids, VersionOptions.Latest, QueryHints.Empty).ToList() + ContentItems = _contentManager + .GetMany(ids, VersionOptions.Latest, QueryHints.Empty).ToList() }; - model.SelectedIds = string.Join(",", field.Ids); + model.SelectedIds = string.Join(",", ids); return shapeHelper.EditorTemplate(TemplateName: "Fields/ContentPicker.Edit", Model: model, Prefix: GetPrefix(field, part)); }); } + private int[] GetDefaultids(ContentPart part, Fields.ContentPickerField field) { + var ids = new int[] { }; + var settings = field.PartFieldDefinition.Settings.GetModel(); + if (!string.IsNullOrWhiteSpace(settings?.DefaultValue)) { + var defaultIds = _tokenizer + .Replace(settings.DefaultValue, + new Dictionary { { "Content", part.ContentItem } }); + if (!string.IsNullOrWhiteSpace(defaultIds)) { + // attempt to parse the string we populated from tokens + ids = ContentPickerField.DecodeIds(defaultIds); + } + } + + return ids; + } + protected override DriverResult Editor(ContentPart part, Fields.ContentPickerField field, IUpdateModel updater, dynamic shapeHelper) { var model = new ContentPickerFieldViewModel { SelectedIds = string.Join(",", field.Ids) }; @@ -63,8 +89,7 @@ protected override DriverResult Editor(ContentPart part, Fields.ContentPickerFie if (String.IsNullOrEmpty(model.SelectedIds)) { field.Ids = new int[0]; - } - else { + } else { field.Ids = model.SelectedIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray(); } @@ -76,14 +101,18 @@ protected override DriverResult Editor(ContentPart part, Fields.ContentPickerFie } protected override void Importing(ContentPart part, Fields.ContentPickerField field, ImportContentContext context) { - var contentItemIds = context.Attribute(field.FieldDefinition.Name + "." + field.Name, "ContentItems"); - if (contentItemIds != null) { - field.Ids = contentItemIds.Split(',') - .Select(context.GetItemFromSession) - .Select(contentItem => contentItem.Id).ToArray(); - } - else { - field.Ids = new int[0]; + // If nothing about the field is inside the context, field is not modified. + // For this reason, check if the current element is inside the ImportContentContext. + var element = context.Data.Element(field.FieldDefinition.Name + "." + field.Name); + if (element != null) { + var contentItemIds = context.Attribute(field.FieldDefinition.Name + "." + field.Name, "ContentItems"); + if (contentItemIds != null) { + field.Ids = contentItemIds.Split(',') + .Select(context.GetItemFromSession) + .Select(contentItem => contentItem.Id).ToArray(); + } else { + field.Ids = new int[0]; + } } } diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Fields/ContentPickerField.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Fields/ContentPickerField.cs index f4ad2b3cfaa..4d0a4049392 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Fields/ContentPickerField.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Fields/ContentPickerField.cs @@ -21,7 +21,7 @@ public IEnumerable ContentItems { } } - private string EncodeIds(ICollection ids) { + private static string EncodeIds(ICollection ids) { if (ids == null || !ids.Any()) { return string.Empty; } @@ -30,12 +30,25 @@ private string EncodeIds(ICollection ids) { return "{" + string.Join("},{", ids.ToArray()) + "}"; } - private int[] DecodeIds(string ids) { + public static int[] DecodeIds(string ids) { if(String.IsNullOrWhiteSpace(ids)) { return new int[0]; } - - return ids.Split(separator, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray(); + // if some of the slices of the string cannot be properly parsed, + // we still will return those that can. + return ids + .Split(separator, StringSplitOptions.RemoveEmptyEntries) + .Select(s => { + int i = -1; + if(int.TryParse(s, out i)) { + return i; + } + // if we can't parse return a negative value + return -1; + }) + // take only those that parsed properly + .Where(i => i > 0) + .ToArray(); } } } diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Handlers/ContentPickerFieldHandler.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Handlers/ContentPickerFieldHandler.cs index 74ea52acbe6..d11d0d99bb4 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Handlers/ContentPickerFieldHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Handlers/ContentPickerFieldHandler.cs @@ -6,14 +6,11 @@ namespace Orchard.ContentPicker.Handlers { public class ContentPickerFieldHandler : ContentHandler { - private readonly IContentManager _contentManager; private readonly IContentDefinitionManager _contentDefinitionManager; public ContentPickerFieldHandler( - IContentManager contentManager, IContentDefinitionManager contentDefinitionManager) { - _contentManager = contentManager; _contentDefinitionManager = contentDefinitionManager; } @@ -30,7 +27,8 @@ protected override void Loading(LoadContentContext context) { foreach (var field in fields) { var localField = field; - field._contentItems.Loader(() => _contentManager.GetMany(localField.Ids, VersionOptions.Published, QueryHints.Empty)); + // Using context content item's ContentManager instead of injected one to avoid lifetime scope exceptions in case of LazyFields. + field._contentItems.Loader(() => context.ContentItem.ContentManager.GetMany(localField.Ids, VersionOptions.Published, QueryHints.Empty)); } } } diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Handlers/ContentPickerFieldLocalizationExtensionHandler.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Handlers/ContentPickerFieldLocalizationExtensionHandler.cs index 7b604f2f10b..2f00e58e869 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Handlers/ContentPickerFieldLocalizationExtensionHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Handlers/ContentPickerFieldLocalizationExtensionHandler.cs @@ -42,7 +42,7 @@ protected override void UpdateEditorShape(UpdateEditorContext context) { var settings = field.PartFieldDefinition.Settings.GetModel(); if (settings.TryToLocalizeItems) { //try to replace items in the field with their translation - var itemsInField = _contentManager.GetMany(field.Ids, VersionOptions.Published, QueryHints.Empty); + var itemsInField = _contentManager.GetMany(field.Ids, VersionOptions.Latest, QueryHints.Empty); if (settings.RemoveItemsWithNoLocalizationPart && itemsInField.Where(ci => !ci.Parts.Any(part => part is LocalizationPart)).Any()) { //keep only items that have a LocalizationPart _orchardServices.Notifier.Warning(T( @@ -92,7 +92,7 @@ protected override void UpdateEditorShape(UpdateEditorContext context) { } if (settings.AssertItemsHaveSameCulture) { //verify that the items in the ContentPickerField are all in the culture of the ContentItem whose editor we are updating - var itemsInField = _contentManager.GetMany(field.Ids, VersionOptions.Published, QueryHints.Empty); + var itemsInField = _contentManager.GetMany(field.Ids, VersionOptions.Latest, QueryHints.Empty); var itemsWithoutLocalizationPart = itemsInField.Where(ci => !ci.Parts.Any(part => part is LocalizationPart)); List badItemIds = itemsInField.Where(ci => ci.Parts.Any(part => part is LocalizationPart && ((LocalizationPart)part).Culture != lPart.Culture)).Select(ci => ci.Id).ToList(); if (itemsWithoutLocalizationPart.Count() > 0) { diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Module.txt b/src/Orchard.Web/Modules/Orchard.ContentPicker/Module.txt index 352b0173ca4..f8e439be2a2 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Module.txt @@ -2,8 +2,8 @@ Name: Orchard.ContentPicker AntiForgery: enabled Author: The Orchard Team Website: http://www.orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: UI for selecting Content Items. Features: Orchard.ContentPicker: diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Orchard.ContentPicker.csproj b/src/Orchard.Web/Modules/Orchard.ContentPicker/Orchard.ContentPicker.csproj index e9dba3b520a..55074b5e1dd 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Orchard.ContentPicker.csproj +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Orchard.ContentPicker.csproj @@ -12,8 +12,8 @@ Properties Orchard.ContentPicker Orchard.ContentPicker - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,9 @@ + + + true @@ -49,49 +52,54 @@ false - - ..\..\..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll - True + + ..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll + + + ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll + + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - - ..\..\..\packages\NHibernate.4.0.1.4000\lib\net40\NHibernate.dll - True + + ..\..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll + + + ..\..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll + + + ..\..\..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll + + - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -177,30 +185,34 @@ {2d1d92bb-4555-4cbe-8d0e-63563d6ce4c6} Orchard.Framework - false + $(MvcBuildViews) {9916839c-39fc-4ceb-a5af-89ca7e87119f} Orchard.Core - false + $(MvcBuildViews) {fbc8b571-ed50-49d8-8d9d-64ab7454a0d6} Orchard.Localization + + {6f759635-13d7-4e94-bcc9-80445d63f117} + Orchard.Tokens + - - - + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) @@ -225,7 +237,7 @@ --> - + @@ -239,7 +251,7 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Properties/AssemblyInfo.cs index 20543296373..01b826c0526 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Properties/AssemblyInfo.cs @@ -31,6 +31,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/ResourceManifest.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/ResourceManifest.cs index 021889434d2..ad8e46a5572 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/ResourceManifest.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/ResourceManifest.cs @@ -5,7 +5,7 @@ public class ResourceManifest : IResourceManifestProvider { public void BuildManifests(ResourceManifestBuilder builder) { var manifest = builder.Add(); manifest.DefineScript("ContentPicker").SetUrl("ContentPicker.js", "ContentPicker.js").SetDependencies("jQuery"); - manifest.DefineScript("SelectableContentTab").SetUrl("SelectableContentTab.js", "SelectableContentTab.js").SetDependencies("jQuery"); + manifest.DefineScript("SelectableContentTab").SetUrl("SelectableContentTab.js?v=1.1", "SelectableContentTab.js?v=1.1").SetDependencies("jQuery"); } } } diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Scripts/SelectableContentTab.js b/src/Orchard.Web/Modules/Orchard.ContentPicker/Scripts/SelectableContentTab.js index 2bc82e19664..cfd8c8a604e 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Scripts/SelectableContentTab.js +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Scripts/SelectableContentTab.js @@ -1,12 +1,18 @@ jQuery(function ($) { Initialize = function () { - - $('.button.addSelected').on('click', function () { - var selectedItems = $('.content-picker-itemCheck:checked'); - var itemsToAdd = new Array(); - $.each(selectedItems, function (index, item) { - var related = $(item).siblings('.content-picker-item').children('.related'); + $('.content-picker-itemCheck').each(function () { + var related = $(this).siblings('.content-picker-item').children('.related'); + + if (window.sessionStorage.getItem(related.data("id")) != null) { + $(this).prop('checked', true); + } + }); + + $('.content-picker-itemCheck').change(function () { + var related = $(this).siblings('.content-picker-item').children('.related'); + + if (this.checked) { var data = { id: related.data("id"), displayText: related.data("display-text"), @@ -16,13 +22,32 @@ displayLink: related.data("display-link"), published: related.data("published") }; - return itemsToAdd.push(data); - }); + + window.sessionStorage.setItem(related.data("id"), JSON.stringify(data)); + } else { + window.sessionStorage.removeItem(related.data("id")); + } + }); + + $('.button.addSelected').on('click', function () { + var itemsToAdd = new Array(); + for (var i = 0; i < sessionStorage.length; i++) { + var key = sessionStorage.key(i); + // only add the item if the key is an integer: other scripts may be + // adding stuff to sessionStorage + if (!isNaN(key - parseInt(key))) { + var data = window.sessionStorage.getItem(sessionStorage.key(i)); + itemsToAdd.push(JSON.parse(data)); + } + } + window.sessionStorage.clear(); window.opener.jQuery[query("callback")](itemsToAdd); window.close(); }); + $('.content-picker-SelectAll').on('click', function () { $('.content-picker-itemCheck').prop('checked', $(this).prop("checked")); + $('.content-picker-itemCheck').change(); }); }; diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Settings/ContentPickerFieldEditorEvents.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Settings/ContentPickerFieldEditorEvents.cs index 7d71205324b..a3e3baec6df 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Settings/ContentPickerFieldEditorEvents.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Settings/ContentPickerFieldEditorEvents.cs @@ -28,6 +28,7 @@ public override IEnumerable PartFieldEditorUpdate(ContentPart builder.WithSetting("ContentPickerFieldSettings.Multiple", model.Multiple.ToString(CultureInfo.InvariantCulture)); builder.WithSetting("ContentPickerFieldSettings.ShowContentTab", model.ShowContentTab.ToString(CultureInfo.InvariantCulture)); builder.WithSetting("ContentPickerFieldSettings.DisplayedContentTypes", model.DisplayedContentTypes); + builder.WithSetting("ContentPickerFieldSettings.DefaultValue", model.DefaultValue); } yield return DefinitionTemplate(model); diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Settings/ContentPickerFieldSettings.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Settings/ContentPickerFieldSettings.cs index eab5555d14b..7fb70b56dfa 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Settings/ContentPickerFieldSettings.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Settings/ContentPickerFieldSettings.cs @@ -10,5 +10,7 @@ public ContentPickerFieldSettings() { public bool ShowContentTab { get; set; } public string DisplayedContentTypes { get; set; } + + public string DefaultValue { get; set; } } } diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Tokens/FieldTokens.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Tokens/FieldTokens.cs index f10bcfb52a8..4b73bded0bb 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Tokens/FieldTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Tokens/FieldTokens.cs @@ -1,7 +1,8 @@ using System; +using System.Linq; using Orchard.ContentManagement; -using Orchard.Events; using Orchard.ContentPicker.Fields; +using Orchard.Events; using Orchard.Localization; namespace Orchard.ContentPicker.Tokens { @@ -28,7 +29,10 @@ public void Describe(dynamic context) { public void Evaluate(dynamic context) { context.For("ContentPickerField") .Token("Content", (Func)(field => field.Ids[0])) - .Chain("Content", "Content", (Func)(field => _contentManager.Get(field.Ids[0]))) + .Chain("Content", "Content", (Func)(field => { + var id = field.Ids.Any() ? field.Ids[0] : 0; + return _contentManager.Get(id); + })) ; } } diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/ContentPicker.Edit.cshtml b/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/ContentPicker.Edit.cshtml index 1de2657e8de..cdf16609754 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/ContentPicker.Edit.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/ContentPicker.Edit.cshtml @@ -16,7 +16,7 @@ var fieldName = Model.FieldName; var baseUrl = Url.Content("~/") + WorkContext.Resolve().RequestUrlPrefix; var types = String.Join(",", (IEnumerable)Model.Types ?? Enumerable.Empty()); -} +}
      - @Html.ItemAdminLink(contentItem) @if (!contentItem.HasPublished()){ - @T("Not Published")} + @Html.ItemAdminLink(null, contentItem, new { ReturnUrl = @Request.Url.ToString()}) @if (!contentItem.HasPublished()){ - @T("Not Published")} @T("Remove") diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/DefinitionTemplates/ContentPickerFieldSettings.cshtml b/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/DefinitionTemplates/ContentPickerFieldSettings.cshtml index 1191c562984..4d6cb9dd63a 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/DefinitionTemplates/ContentPickerFieldSettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/DefinitionTemplates/ContentPickerFieldSettings.cshtml @@ -14,7 +14,7 @@
    - @Html.TextAreaFor(m => m.Hint, new { @class = "text medium", rows = "5" } ) + @Html.TextAreaFor(m => m.Hint, new { @class = "text medium", rows = "5" }) @T("The help text is written under the field when authors are selecting content items.") @Html.ValidationMessageFor(m => m.Hint)
    @@ -27,7 +27,16 @@
    - @Html.TextBoxFor(m => m.DisplayedContentTypes) + @Html.TextBoxFor(m => m.DisplayedContentTypes) @T("A comma separated value of all the content types or content parts to display.")
    +
    +
    + + @Html.TextBoxFor(m => m.DefaultValue, new { @class = "text large tokenized"}) + @T("A comma separated list of the ids of selected Items. It also accepts {{ or }} as separators, in line with the serialization normally used for this field.") +
    +
    + +@Display.TokenHint() \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/EditorTemplates/Fields/ContentPickerLocalization.Edit.cshtml b/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/EditorTemplates/Fields/ContentPickerLocalization.Edit.cshtml index 41f232d1a76..9ba7a096446 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/EditorTemplates/Fields/ContentPickerLocalization.Edit.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Views/EditorTemplates/Fields/ContentPickerLocalization.Edit.cshtml @@ -17,13 +17,18 @@ //We will use a script to find the fieldset for the field we are currently processing. //The fieldset contains a span of class "hint". We will add tryTranslateMsg to it. + //We will check if the field exists in the page DOM, just in case a Placement.info suppresses it. string dataPartName = HttpUtility.JavaScriptStringEncode(Model.Part.PartDefinition.Name); string dataFieldName = HttpUtility.JavaScriptStringEncode(Model.Field.PartFieldDefinition.Name); } + @using (Script.Foot()) { \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentPreview/Views/Preview/Render.cshtml b/src/Orchard.Web/Modules/Orchard.ContentPreview/Views/Preview/Render.cshtml new file mode 100644 index 00000000000..2d1e194ecd8 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.ContentPreview/Views/Preview/Render.cshtml @@ -0,0 +1,3 @@ +@Html.ValidationSummary() + +@Display(Model) \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentPreview/Web.config b/src/Orchard.Web/Modules/Orchard.ContentPreview/Web.config new file mode 100644 index 00000000000..74130ebcee3 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.ContentPreview/Web.config @@ -0,0 +1,86 @@ + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentPreview/packages.config b/src/Orchard.Web/Modules/Orchard.ContentPreview/packages.config new file mode 100644 index 00000000000..64f769b11ad --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.ContentPreview/packages.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs index dbb560b0265..6c1d34e3aa0 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Controllers/AdminController.cs @@ -28,19 +28,19 @@ public class AdminController : Controller, IUpdateModel { private readonly ShellSettings _settings; public AdminController( - IOrchardServices orchardServices, - IContentDefinitionService contentDefinitionService, + IOrchardServices orchardServices, + IContentDefinitionService contentDefinitionService, IContentDefinitionManager contentDefinitionManager, IPlacementService placementService, Lazy> settingsManagerEventHandlers, - ShellSettings settings - ) { + ShellSettings settings) { Services = orchardServices; _contentDefinitionService = contentDefinitionService; _contentDefinitionManager = contentDefinitionManager; _placementService = placementService; _settingsManagerEventHandlers = settingsManagerEventHandlers; _settings = settings; + T = NullLocalizer.Instance; } @@ -64,7 +64,7 @@ public ActionResult Create(string suggestion) { if (!Services.Authorizer.Authorize(Permissions.EditContentTypes, T("Not allowed to create a content type."))) return new HttpUnauthorizedResult(); - return View(new CreateTypeViewModel { DisplayName = suggestion, Name = suggestion.ToSafeName() }); + return View(new CreateTypeViewModel { DisplayName = suggestion?.Trim(), Name = suggestion?.ToSafeName() }); } [HttpPost, ActionName("Create")] @@ -72,37 +72,33 @@ public ActionResult CreatePOST(CreateTypeViewModel viewModel) { if (!Services.Authorizer.Authorize(Permissions.EditContentTypes, T("Not allowed to create a content type."))) return new HttpUnauthorizedResult(); - viewModel.DisplayName = viewModel.DisplayName ?? String.Empty; - viewModel.Name = viewModel.Name ?? String.Empty; - if (String.IsNullOrWhiteSpace(viewModel.DisplayName)) { - ModelState.AddModelError("DisplayName", T("The Display Name name can't be empty.").ToString()); - } + ValidateDisplayName(viewModel.DisplayName); - if (String.IsNullOrWhiteSpace(viewModel.Name)) { - ModelState.AddModelError("Name", T("The Content Type Id can't be empty.").ToString()); + // Additional Display Name validation. + if (!string.IsNullOrWhiteSpace(viewModel.DisplayName) && + _contentDefinitionService.GetTypes().Any(t => string.Equals(t.DisplayName.Trim(), viewModel.DisplayName.Trim(), StringComparison.OrdinalIgnoreCase))) { + ModelState.AddModelError("DisplayName", T("A content type with this display name already exists.").Text); } - if (_contentDefinitionService.GetTypes().Any(t => String.Equals(t.Name.Trim(), viewModel.Name.Trim(), StringComparison.OrdinalIgnoreCase))) { - ModelState.AddModelError("Name", T("A type with the same Id already exists.").ToString()); - } + ValidateTechnicalName(viewModel.Name); - if (!String.IsNullOrWhiteSpace(viewModel.Name) && !viewModel.Name[0].IsLetter()) { - ModelState.AddModelError("Name", T("The technical name must start with a letter.").ToString()); - } - - if (_contentDefinitionService.GetTypes().Any(t => String.Equals(t.DisplayName.Trim(), viewModel.DisplayName.Trim(), StringComparison.OrdinalIgnoreCase))) { - ModelState.AddModelError("DisplayName", T("A type with the same Display Name already exists.").ToString()); + // Additional Technical Name validation. + if (!string.IsNullOrWhiteSpace(viewModel.Name) && + _contentDefinitionService.GetTypes().Any(t => string.Equals(t.Name.ToSafeName(), viewModel.Name.ToSafeName(), StringComparison.OrdinalIgnoreCase))) { + ModelState.AddModelError("Name", T("A content type with this technical name already exists.").Text); } if (!ModelState.IsValid) { Services.TransactionManager.Cancel(); + return View(viewModel); } + var contentTypeDefinition = _contentDefinitionService.AddType(viewModel.Name, viewModel.DisplayName); - - // adds CommonPart by default + + // CommonPart is added by default to all Content Types. _contentDefinitionService.AddPartToType("CommonPart", viewModel.Name); var typeViewModel = new EditTypeViewModel(contentTypeDefinition); @@ -116,14 +112,14 @@ public ActionResult CreatePOST(CreateTypeViewModel viewModel) { public ActionResult ContentTypeName(string displayName, int version) { return Json(new { result = _contentDefinitionService.GenerateContentTypeNameFromDisplayName(displayName), - version = version + version }); } public ActionResult FieldName(string partName, string displayName, int version) { return Json(new { result = _contentDefinitionService.GenerateFieldNameFromDisplayName(partName, displayName), - version = version + version }); } @@ -133,8 +129,7 @@ public ActionResult Edit(string id) { var typeViewModel = _contentDefinitionService.GetType(id); - if (typeViewModel == null) - return HttpNotFound(); + if (typeViewModel == null) return HttpNotFound(); return View(typeViewModel); } @@ -145,12 +140,73 @@ public ActionResult EditPlacement(string id) { var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(id); - if (contentTypeDefinition == null) - return HttpNotFound(); - + if (contentTypeDefinition == null) return HttpNotFound(); + + //Grouping Tabs > Cards > Shapes + var grouped = _placementService + // Get a collection of objects that describe the placement for all shapes + // in the editor view for a ContentItem of the given ContentType + .GetEditorPlacement(id) + // Order all those shapes based on their position + .OrderBy(x => x.PlacementInfo.GetPosition(), new FlatPositionComparer()) + // Then alphabetically by their shape type + .ThenBy(x => x.PlacementSettings.ShapeType) + // only pick those shapes that live int the "Content" zone + .Where(e => e.PlacementSettings.Zone == "Content") + // Form groups whose key is a string like {tabName}%{cardName}. Items + // in a group represent the shapes that will be in the card called {cardName} + // in the tab called {tabName}. + .GroupBy(g => g.PlacementInfo.GetTab() + "%" + g.PlacementInfo.GetCard()) + // Transform each of those groups in an object representing the single cards. + // Each of these objects contains the name of the tab that contains it, as + // well as the list of shape placements in that card + .Select(x => + new Card { + Name = x.Key.Split('%')[1], + TabName = x.Key.Split('%')[0], + Placements = x.ToList() + }) + // Group cards by tab + .GroupBy(x => x.TabName) + // Since each of those groups "represents" a card, we actually make it into one. + .Select(x => + new Tab { + Name = x.Key, + Cards = x.ToList() + }) + // Make the collection into a List because it's easy to interact with it + // (see later in the code) + .ToList(); + var listPlacements = grouped + // By selecting all placements from the Tab objects we built earlier, we have + // them ordered nicely + .SelectMany(x => x.Cards.SelectMany(m => m.Placements)) + .ToList(); + // We want to have an un-named "default" Tab for shapes, in case none was defined + Tab content; + if (grouped.Any(x => string.IsNullOrWhiteSpace(x.Name))) { + // Because of the way the elements of the list have been ordered above, + // if there is a Tab with empty name, it is the first in the list. + content = grouped[0]; + grouped.Remove(content); + } else { + content = new Tab { + Name = "", + Cards = new List { new Card { Name = "", TabName = "", Placements = new List() } } + }; + } + // In each Tab, we want to have a "default" un-named Card. This will simplfy + // UI interactions, because it ensures that each Tab has some place we can drop + // shapes in. + for (int i = 0; i < grouped.Count(); i++) { + if (!grouped[i].Cards.Any(x => string.IsNullOrEmpty(x.Name))) { + grouped[i].Cards.Insert(0, new Card { Name = "", TabName = grouped[i].Name, Placements = new List() }); + } + } var placementModel = new EditPlacementViewModel { - PlacementSettings = contentTypeDefinition.GetPlacement(PlacementType.Editor), - AllPlacements = _placementService.GetEditorPlacement(id).OrderBy(x => x.PlacementSettings.Position, new FlatPositionComparer()).ThenBy(x => x.PlacementSettings.ShapeType).ToList(), + Content = content, + AllPlacements = listPlacements, + Tabs = grouped, ContentTypeDefinition = contentTypeDefinition, }; @@ -165,37 +221,27 @@ public ActionResult EditPlacementPost(string id, EditPlacementViewModel viewMode var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(id); - if (contentTypeDefinition == null) - return HttpNotFound(); - - var allPlacements = _placementService.GetEditorPlacement(id).ToList(); - var result = new List(contentTypeDefinition.GetPlacement(PlacementType.Editor)); + if (contentTypeDefinition == null) return HttpNotFound(); contentTypeDefinition.ResetPlacement(PlacementType.Editor); - foreach(var driverPlacement in viewModel.AllPlacements) { - // if the placement has changed, persist it - if (!allPlacements.Any(x => x.PlacementSettings.Equals(driverPlacement.PlacementSettings))) { - result = result.Where(x => !x.IsSameAs(driverPlacement.PlacementSettings)).ToList(); - result.Add(driverPlacement.PlacementSettings); - } - } - - foreach(var placementSetting in result) { - contentTypeDefinition.Placement(PlacementType.Editor, - placementSetting.ShapeType, - placementSetting.Differentiator, - placementSetting.Zone, - placementSetting.Position); + foreach (var placement in viewModel.AllPlacements) { + var placementSetting = placement.PlacementSettings; + contentTypeDefinition.Placement( + PlacementType.Editor, + placementSetting.ShapeType, + placementSetting.Differentiator, + placementSetting.Zone, + placementSetting.Position); } - // persist changes + // Persist placement changes. _contentDefinitionManager.StoreTypeDefinition(contentTypeDefinition); _settingsManagerEventHandlers.Value.Invoke(x => x.Saved(_settings), Logger); - return RedirectToAction("EditPlacement", new {id}); + return RedirectToAction("EditPlacement", new { id }); } [HttpPost, ActionName("EditPlacement")] @@ -206,12 +252,11 @@ public ActionResult EditPlacementRestorePost(string id, EditPlacementViewModel v var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(id); - if (contentTypeDefinition == null) - return HttpNotFound(); + if (contentTypeDefinition == null) return HttpNotFound(); contentTypeDefinition.ResetPlacement(PlacementType.Editor); - // persist changes + // Persist placement reset. _contentDefinitionManager.StoreTypeDefinition(contentTypeDefinition); _settingsManagerEventHandlers.Value.Invoke(x => x.Saved(_settings), Logger); @@ -227,28 +272,33 @@ public ActionResult EditPOST(string id) { var typeViewModel = _contentDefinitionService.GetType(id); - if (typeViewModel == null) - return HttpNotFound(); + if (typeViewModel == null) return HttpNotFound(); var edited = new EditTypeViewModel(); + TryUpdateModel(edited); - typeViewModel.DisplayName = edited.DisplayName ?? string.Empty; - if ( String.IsNullOrWhiteSpace(typeViewModel.DisplayName) ) { - ModelState.AddModelError("DisplayName", T("The Content Type name can't be empty.").ToString()); - } - if ( _contentDefinitionService.GetTypes().Any(t => String.Equals(t.DisplayName.Trim(), typeViewModel.DisplayName.Trim(), StringComparison.OrdinalIgnoreCase) && !String.Equals(t.Name, id)) ) { - ModelState.AddModelError("DisplayName", T("A type with the same name already exists.").ToString()); + ValidateDisplayName(edited.DisplayName); + + // Additional Display Name validation. + if (!string.IsNullOrWhiteSpace(edited.DisplayName) && + _contentDefinitionService.GetTypes().Any(t => + !string.Equals(t.Name, edited.Name, StringComparison.OrdinalIgnoreCase) && + string.Equals(t.DisplayName.Trim(), edited.DisplayName.Trim(), StringComparison.OrdinalIgnoreCase))) { + ModelState.AddModelError("DisplayName", T("A content type with this display name already exists.").Text); } - if (!ModelState.IsValid) - return View(typeViewModel); + if (!ModelState.IsValid) return View(typeViewModel); + + + typeViewModel.DisplayName = edited.DisplayName; _contentDefinitionService.AlterType(typeViewModel, this); if (!ModelState.IsValid) { Services.TransactionManager.Cancel(); + return View(typeViewModel); } @@ -265,13 +315,12 @@ public ActionResult Delete(string id) { var typeViewModel = _contentDefinitionService.GetType(id); - if (typeViewModel == null) - return HttpNotFound(); + if (typeViewModel == null) return HttpNotFound(); _contentDefinitionService.RemoveType(id, true); Services.Notifier.Success(T("\"{0}\" has been removed.", typeViewModel.DisplayName)); - + return RedirectToAction("List"); } @@ -281,14 +330,13 @@ public ActionResult AddPartsTo(string id) { var typeViewModel = _contentDefinitionService.GetType(id); - if (typeViewModel == null) - return HttpNotFound(); + if (typeViewModel == null) return HttpNotFound(); var typePartNames = new HashSet(typeViewModel.Parts.Select(tvm => tvm.PartDefinition.Name)); var viewModel = new AddPartsViewModel { Type = typeViewModel, - PartSelections = _contentDefinitionService.GetParts(false/*metadataPartsOnly*/) + PartSelections = _contentDefinitionService.GetParts(metadataPartsOnly: false) .Where(cpd => !typePartNames.Contains(cpd.Name) && cpd.Settings.GetModel().Attachable) .Select(cpd => new PartSelectionViewModel { PartName = cpd.Name, PartDisplayName = cpd.DisplayName, PartDescription = cpd.Description }) .ToList() @@ -304,25 +352,26 @@ public ActionResult AddPartsToPOST(string id) { var typeViewModel = _contentDefinitionService.GetType(id); - if (typeViewModel == null) - return HttpNotFound(); + if (typeViewModel == null) return HttpNotFound(); var viewModel = new AddPartsViewModel(); - if (!TryUpdateModel(viewModel)) - return AddPartsTo(id); + + if (!TryUpdateModel(viewModel)) return AddPartsTo(id); var partsToAdd = viewModel.PartSelections.Where(ps => ps.IsSelected).Select(ps => ps.PartName); foreach (var partToAdd in partsToAdd) { _contentDefinitionService.AddPartToType(partToAdd, typeViewModel.Name); + Services.Notifier.Success(T("The \"{0}\" part has been added.", partToAdd)); } if (!ModelState.IsValid) { Services.TransactionManager.Cancel(); + return AddPartsTo(id); } - return RedirectToAction("Edit", new {id}); + return RedirectToAction("Edit", new { id }); } public ActionResult RemovePartFrom(string id) { @@ -332,12 +381,12 @@ public ActionResult RemovePartFrom(string id) { var typeViewModel = _contentDefinitionService.GetType(id); var viewModel = new RemovePartViewModel(); - if (typeViewModel == null - || !TryUpdateModel(viewModel) - || !typeViewModel.Parts.Any(p => p.PartDefinition.Name == viewModel.Name)) + if (typeViewModel == null || !TryUpdateModel(viewModel) || + !typeViewModel.Parts.Any(p => p.PartDefinition.Name == viewModel.Name)) return HttpNotFound(); viewModel.Type = typeViewModel; + return View(viewModel); } @@ -349,9 +398,8 @@ public ActionResult RemovePartFromPOST(string id) { var typeViewModel = _contentDefinitionService.GetType(id); var viewModel = new RemovePartViewModel(); - if (typeViewModel == null - || !TryUpdateModel(viewModel) - || !typeViewModel.Parts.Any(p => p.PartDefinition.Name == viewModel.Name)) + if (typeViewModel == null || !TryUpdateModel(viewModel) || + !typeViewModel.Parts.Any(p => p.PartDefinition.Name == viewModel.Name)) return HttpNotFound(); _contentDefinitionService.RemovePartFromType(viewModel.Name, typeViewModel.Name); @@ -359,12 +407,13 @@ public ActionResult RemovePartFromPOST(string id) { if (!ModelState.IsValid) { Services.TransactionManager.Cancel(); viewModel.Type = typeViewModel; + return View(viewModel); } Services.Notifier.Success(T("The \"{0}\" part has been removed.", viewModel.Name)); - return RedirectToAction("Edit", new {id}); + return RedirectToAction("Edit", new { id }); } #endregion @@ -374,7 +423,7 @@ public ActionResult RemovePartFromPOST(string id) { public ActionResult ListParts() { return View(new ListContentPartsViewModel { // only user-defined parts (not code as they are not configurable) - Parts = _contentDefinitionService.GetParts(true/*metadataPartsOnly*/) + Parts = _contentDefinitionService.GetParts(metadataPartsOnly: true) }); } @@ -382,7 +431,7 @@ public ActionResult CreatePart(string suggestion) { if (!Services.Authorizer.Authorize(Permissions.EditContentTypes, T("Not allowed to create a content part."))) return new HttpUnauthorizedResult(); - return View(new CreatePartViewModel { Name = suggestion.ToSafeName() }); + return View(new CreatePartViewModel { Name = suggestion?.ToSafeName() }); } [HttpPost, ActionName("CreatePart")] @@ -390,20 +439,28 @@ public ActionResult CreatePartPOST(CreatePartViewModel viewModel) { if (!Services.Authorizer.Authorize(Permissions.EditContentTypes, T("Not allowed to create a content part."))) return new HttpUnauthorizedResult(); - if (_contentDefinitionManager.GetPartDefinition(viewModel.Name) != null) - ModelState.AddModelError("Name", T("Cannot add part named '{0}'. It already exists.", viewModel.Name).ToString()); - if (!ModelState.IsValid) - return View(viewModel); + ValidateTechnicalName(viewModel.Name); + + // Additional Technical Name validation. + if (!string.IsNullOrWhiteSpace(viewModel.Name) && + _contentDefinitionManager.ListPartDefinitions().Any(t => string.Equals(t.Name.ToSafeName(), viewModel.Name.ToSafeName(), StringComparison.OrdinalIgnoreCase))) { + ModelState.AddModelError("Name", T("A content part with this technical name already exists.").Text); + } + + if (!ModelState.IsValid) return View(viewModel); + var partViewModel = _contentDefinitionService.AddPart(viewModel); if (partViewModel == null) { Services.Notifier.Error(T("The content part could not be created.")); + return View(viewModel); } Services.Notifier.Success(T("The \"{0}\" content part has been created.", partViewModel.Name)); + return RedirectToAction("EditPart", new { id = partViewModel.Name }); } @@ -413,8 +470,7 @@ public ActionResult EditPart(string id) { var partViewModel = _contentDefinitionService.GetPart(id); - if (partViewModel == null) - return HttpNotFound(); + if (partViewModel == null) return HttpNotFound(); return View(partViewModel); } @@ -427,16 +483,15 @@ public ActionResult EditPartPOST(string id) { var partViewModel = _contentDefinitionService.GetPart(id); - if (partViewModel == null) - return HttpNotFound(); + if (partViewModel == null) return HttpNotFound(); - if (!TryUpdateModel(partViewModel)) - return View(partViewModel); + if (!TryUpdateModel(partViewModel)) return View(partViewModel); _contentDefinitionService.AlterPart(partViewModel, this); if (!ModelState.IsValid) { Services.TransactionManager.Cancel(); + return View(partViewModel); } @@ -447,15 +502,13 @@ public ActionResult EditPartPOST(string id) { [HttpPost, ActionName("EditPart")] [FormValueRequired("submit.Delete")] - public ActionResult DeletePart(string id) - { + public ActionResult DeletePart(string id) { if (!Services.Authorizer.Authorize(Permissions.EditContentTypes, T("Not allowed to delete a content part."))) return new HttpUnauthorizedResult(); var partViewModel = _contentDefinitionService.GetPart(id); - if (partViewModel == null) - return HttpNotFound(); + if (partViewModel == null) return HttpNotFound(); _contentDefinitionService.RemovePart(id); @@ -470,13 +523,13 @@ public ActionResult AddFieldTo(string id) { var partViewModel = _contentDefinitionService.GetPart(id); + // If the specified Part doesn't exist, try to find a matching Type, + // where the implicit Part with the same name can be created to store Fields. if (partViewModel == null) { - //id passed in might be that of a type w/ no implicit field var typeViewModel = _contentDefinitionService.GetType(id); - if (typeViewModel != null) - partViewModel = new EditPartViewModel(new ContentPartDefinition(id)); - else - return HttpNotFound(); + + if (typeViewModel == null) return HttpNotFound(); + else partViewModel = new EditPartViewModel(new ContentPartDefinition(id)); } var viewModel = new AddFieldViewModel { @@ -494,48 +547,28 @@ public ActionResult AddFieldToPOST(AddFieldViewModel viewModel, string id) { var partViewModel = _contentDefinitionService.GetPart(id); var typeViewModel = _contentDefinitionService.GetType(id); - if (partViewModel == null) { - // id passed in might be that of a type w/ no implicit field - if (typeViewModel != null) { - partViewModel = new EditPartViewModel {Name = typeViewModel.Name}; - _contentDefinitionService.AddPart(new CreatePartViewModel {Name = partViewModel.Name}); - _contentDefinitionService.AddPartToType(partViewModel.Name, typeViewModel.Name); - } - else { - return HttpNotFound(); - } - } - viewModel.DisplayName = viewModel.DisplayName ?? String.Empty; - viewModel.DisplayName = viewModel.DisplayName.Trim(); - viewModel.Name = viewModel.Name ?? String.Empty; + if (partViewModel == null && typeViewModel == null) return HttpNotFound(); - if (String.IsNullOrWhiteSpace(viewModel.DisplayName)) { - ModelState.AddModelError("DisplayName", T("The Display Name name can't be empty.").ToString()); - } - if (String.IsNullOrWhiteSpace(viewModel.Name)) { - ModelState.AddModelError("Name", T("The Technical Name can't be empty.").ToString()); - } + ValidateDisplayName(viewModel.DisplayName); - if (_contentDefinitionService.GetPart(partViewModel.Name).Fields.Any(t => String.Equals(t.Name.Trim(), viewModel.Name.Trim(), StringComparison.OrdinalIgnoreCase))) { - ModelState.AddModelError("Name", T("A field with the same name already exists.").ToString()); + // Additional Display Name validation. + if (partViewModel != null && !string.IsNullOrWhiteSpace(viewModel.DisplayName) && + partViewModel.Fields.Any(t => string.Equals(t.DisplayName.Trim(), viewModel.DisplayName.Trim(), StringComparison.OrdinalIgnoreCase))) { + ModelState.AddModelError("DisplayName", T("A content field with this display name already exists.").Text); } - if (!String.IsNullOrWhiteSpace(viewModel.Name) && !viewModel.Name[0].IsLetter()) { - ModelState.AddModelError("Name", T("The technical name must start with a letter.").ToString()); - } - - if (!String.Equals(viewModel.Name, viewModel.Name.ToSafeName(), StringComparison.OrdinalIgnoreCase)) { - ModelState.AddModelError("Name", T("The technical name contains invalid characters.").ToString()); - } + ValidateTechnicalName(viewModel.Name); - if (_contentDefinitionService.GetPart(partViewModel.Name).Fields.Any(t => String.Equals(t.DisplayName.Trim(), Convert.ToString(viewModel.DisplayName).Trim(), StringComparison.OrdinalIgnoreCase))) { - ModelState.AddModelError("DisplayName", T("A field with the same Display Name already exists.").ToString()); + // Additional Technical Name validation. + if (partViewModel != null && !string.IsNullOrWhiteSpace(viewModel.Name) && + partViewModel.Fields.Any(t => string.Equals(t.Name.ToSafeName(), viewModel.Name.ToSafeName(), StringComparison.OrdinalIgnoreCase))) { + ModelState.AddModelError("Name", T("A content field with this technical name already exists.").Text); } if (!ModelState.IsValid) { - viewModel.Part = partViewModel; + viewModel.Part = partViewModel ?? new EditPartViewModel { Name = typeViewModel.Name }; viewModel.Fields = _contentDefinitionService.GetFields(); Services.TransactionManager.Cancel(); @@ -543,22 +576,28 @@ public ActionResult AddFieldToPOST(AddFieldViewModel viewModel, string id) { return View(viewModel); } + + // If the specified Part doesn't exist, create an implicit , + // where the implicit Part with the same name can be created to store Fields. + if (partViewModel == null) { + partViewModel = _contentDefinitionService.AddPart(new CreatePartViewModel { Name = typeViewModel.Name }); + _contentDefinitionService.AddPartToType(partViewModel.Name, typeViewModel.Name); + } + + try { _contentDefinitionService.AddFieldToPart(viewModel.Name, viewModel.DisplayName, viewModel.FieldTypeName, partViewModel.Name); } catch (Exception ex) { Services.Notifier.Error(T("The \"{0}\" field was not added. {1}", viewModel.DisplayName, ex.Message)); Services.TransactionManager.Cancel(); + return AddFieldTo(id); } Services.Notifier.Success(T("The \"{0}\" field has been added.", viewModel.DisplayName)); - if (typeViewModel != null) { - return RedirectToAction("Edit", new {id}); - } - - return RedirectToAction("EditPart", new { id }); + return typeViewModel == null ? RedirectToAction("EditPart", new { id }) : RedirectToAction("Edit", new { id }); } public ActionResult EditField(string id, string name) { @@ -567,15 +606,11 @@ public ActionResult EditField(string id, string name) { var partViewModel = _contentDefinitionService.GetPart(id); - if (partViewModel == null) { - return HttpNotFound(); - } + if (partViewModel == null) return HttpNotFound(); var fieldViewModel = partViewModel.Fields.FirstOrDefault(x => x.Name == name); - if(fieldViewModel == null) { - return HttpNotFound(); - } + if (fieldViewModel == null) return HttpNotFound(); var viewModel = new EditFieldNameViewModel { Name = fieldViewModel.Name, @@ -591,50 +626,37 @@ public ActionResult EditFieldPOST(string id, EditFieldNameViewModel viewModel) { if (!Services.Authorizer.Authorize(Permissions.EditContentTypes, T("Not allowed to edit a content type."))) return new HttpUnauthorizedResult(); - if (viewModel == null) - return HttpNotFound(); + if (viewModel == null) return HttpNotFound(); var partViewModel = _contentDefinitionService.GetPart(id); - if (partViewModel == null) { - return HttpNotFound(); - } + if (partViewModel == null) return HttpNotFound(); - // prevent null reference exception in validation - viewModel.DisplayName = viewModel.DisplayName ?? String.Empty; - - // remove extra spaces - viewModel.DisplayName = viewModel.DisplayName.Trim(); - if (String.IsNullOrWhiteSpace(viewModel.DisplayName)) { - ModelState.AddModelError("DisplayName", T("The Display Name name can't be empty.").ToString()); - } - - if (_contentDefinitionService.GetPart(partViewModel.Name).Fields.Any(t => t.Name != viewModel.Name && String.Equals(t.DisplayName.Trim(), viewModel.DisplayName.Trim(), StringComparison.OrdinalIgnoreCase))) { - ModelState.AddModelError("DisplayName", T("A field with the same Display Name already exists.").ToString()); - } + ValidateDisplayName(viewModel.Name); - if (!ModelState.IsValid) { - return View(viewModel); + // Additional Display Name validation. + if (!string.IsNullOrWhiteSpace(viewModel.DisplayName) && + partViewModel.Fields.Any(f => + !string.Equals(f.Name, viewModel.Name, StringComparison.OrdinalIgnoreCase) && + string.Equals(f.DisplayName.Trim(), viewModel.DisplayName.Trim(), StringComparison.OrdinalIgnoreCase))) { + ModelState.AddModelError("DisplayName", T("A content field with this display name already exists on this content part.").Text); } + if (!ModelState.IsValid) return View(viewModel); + + var field = _contentDefinitionManager.GetPartDefinition(id).Fields.FirstOrDefault(x => x.Name == viewModel.Name); - if(field == null) { - return HttpNotFound(); - } + if (field == null) return HttpNotFound(); _contentDefinitionService.AlterField(partViewModel, viewModel); Services.Notifier.Success(T("Display name changed to {0}.", viewModel.DisplayName)); - // redirect to the type editor if a type exists with this name - var typeViewModel = _contentDefinitionService.GetType(id); - if (typeViewModel != null) { - return RedirectToAction("Edit", new { id }); - } - - return RedirectToAction("EditPart", new { id }); + // Redirect to the type editor if a type exists with this name. + return _contentDefinitionService.GetType(id) == null ? + RedirectToAction("EditPart", new { id }) : RedirectToAction("Edit", new { id }); } public ActionResult RemoveFieldFrom(string id) { @@ -644,12 +666,13 @@ public ActionResult RemoveFieldFrom(string id) { var partViewModel = _contentDefinitionService.GetPart(id); var viewModel = new RemoveFieldViewModel(); - if (partViewModel == null - || !TryUpdateModel(viewModel) - || !partViewModel.Fields.Any(p => p.Name == viewModel.Name)) + + if (partViewModel == null || !TryUpdateModel(viewModel) || + !partViewModel.Fields.Any(p => p.Name == viewModel.Name)) return HttpNotFound(); viewModel.Part = partViewModel; + return View(viewModel); } @@ -661,9 +684,8 @@ public ActionResult RemoveFieldFromPOST(string id) { var partViewModel = _contentDefinitionService.GetPart(id); var viewModel = new RemoveFieldViewModel(); - if (partViewModel == null - || !TryUpdateModel(viewModel) - || !partViewModel.Fields.Any(p => p.Name == viewModel.Name)) + if (partViewModel == null || !TryUpdateModel(viewModel) || + !partViewModel.Fields.Any(p => p.Name == viewModel.Name)) return HttpNotFound(); _contentDefinitionService.RemoveFieldFromPart(viewModel.Name, partViewModel.Name); @@ -671,21 +693,49 @@ public ActionResult RemoveFieldFromPOST(string id) { if (!ModelState.IsValid) { Services.TransactionManager.Cancel(); viewModel.Part = partViewModel; + return View(viewModel); } Services.Notifier.Success(T("The \"{0}\" field has been removed.", viewModel.Name)); - if (_contentDefinitionService.GetType(id) != null) - return RedirectToAction("Edit", new { id }); - - return RedirectToAction("EditPart", new { id }); + // Redirect to the type editor if a type exists with this name. + return _contentDefinitionService.GetType(id) == null ? + RedirectToAction("EditPart", new { id }) : RedirectToAction("Edit", new { id }); } #endregion + + private void ValidateDisplayName(string displayName) { + if (string.IsNullOrWhiteSpace(displayName)) { + ModelState.AddModelError("DisplayName", T("The display name name can't be empty.").Text); + } + else if (!string.Equals(displayName, displayName.Trim(), StringComparison.OrdinalIgnoreCase)) { + ModelState.AddModelError("DisplayName", T("The display name starts and/or ends with whitespace characters.").Text); + } + } + + private void ValidateTechnicalName(string technicalName) { + if (string.IsNullOrWhiteSpace(technicalName)) { + ModelState.AddModelError("Name", T("The technical name (Id) can't be empty.").Text); + } + else { + var safeTechnicalName = technicalName.ToSafeName(); + + if (!string.Equals(technicalName, safeTechnicalName, StringComparison.OrdinalIgnoreCase)) { + ModelState.AddModelError("Name", T("The technical name contains invalid (non-alphanumeric) characters.").Text); + } + + if (!safeTechnicalName.FirstOrDefault().IsLetter()) { + ModelState.AddModelError("Name", T("The technical name must start with a letter.").Text); + } + } + } + + bool IUpdateModel.TryUpdateModel(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) { - return base.TryUpdateModel(model, prefix, includeProperties, excludeProperties); + return TryUpdateModel(model, prefix, includeProperties, excludeProperties); } void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) { diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Migrations.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/Migrations.cs index 6d5592a709e..7b345b49fe9 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Migrations.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Migrations.cs @@ -22,7 +22,7 @@ public int Create() { return 1; } - public int UpgradeFrom1() { + public int UpdateFrom1() { foreach (var typeDefinition in _contentDefinitionManager.ListTypeDefinitions()) { if (typeDefinition.Settings.ContainsKey("ContentTypeSettings.Creatable") && Convert.ToBoolean(typeDefinition.Settings["ContentTypeSettings.Creatable"], CultureInfo.InvariantCulture)) { typeDefinition.Settings["ContentTypeSettings.Securable"] = "True"; diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Module.txt b/src/Orchard.Web/Modules/Orchard.ContentTypes/Module.txt index 3dac6a5f372..897eeaf1626 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: ContentTypes modules enables the creation and alteration of content types not based on code. Dependencies: Contents Category: Content diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Orchard.ContentTypes.csproj b/src/Orchard.Web/Modules/Orchard.ContentTypes/Orchard.ContentTypes.csproj index 4f9cf80c1c4..65f1b73d23f 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Orchard.ContentTypes.csproj +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Orchard.ContentTypes.csproj @@ -13,8 +13,8 @@ Properties Orchard.ContentTypes Orchard.ContentTypes - v4.5.2 - false + v4.8 + 7.3 false @@ -27,6 +27,9 @@ + + + true @@ -49,10 +52,12 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -63,28 +68,22 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -139,12 +138,12 @@ - + @@ -180,12 +179,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {CDE24A24-01D3-403C-84B9-37722E18DFB7} @@ -213,7 +212,7 @@ - + 10.0 @@ -241,10 +240,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Permissions.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/Permissions.cs index 66355b2694f..697c17ede07 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Permissions.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Permissions.cs @@ -4,8 +4,8 @@ namespace Orchard.ContentTypes { public class Permissions : IPermissionProvider { - public static readonly Permission ViewContentTypes = new Permission { Name = "ViewContentTypes", Description = "View content types." }; - public static readonly Permission EditContentTypes = new Permission { Name = "EditContentTypes", Description = "Edit content types." }; + public static readonly Permission ViewContentTypes = new Permission { Name = "ViewContentTypes", Description = "View content types" }; + public static readonly Permission EditContentTypes = new Permission { Name = "EditContentTypes", Description = "Edit content types" }; public virtual Feature Feature { get; set; } diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/Properties/AssemblyInfo.cs index da7fddd760f..94977202e79 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/ResourceManifest.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/ResourceManifest.cs index 8d15d2c0a8d..57795d0ad34 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/ResourceManifest.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/ResourceManifest.cs @@ -4,6 +4,10 @@ namespace Orchard.ContentTypes { public class ResourceManifest : IResourceManifestProvider { public void BuildManifests(ResourceManifestBuilder builder) { builder.Add().DefineStyle("ContentTypesAdmin").SetUrl("orchard-contenttypes-admin.css"); + + builder.Add().DefineScript("PlacementEditor") + .SetUrl("admin-placementeditor.js") + .SetDependencies("jQueryUI_Sortable"); } } } diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Scripts/admin-placementeditor.js b/src/Orchard.Web/Modules/Orchard.ContentTypes/Scripts/admin-placementeditor.js new file mode 100644 index 00000000000..ab64293337c --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Scripts/admin-placementeditor.js @@ -0,0 +1,169 @@ +(function ($) { + var assignPositions = function () { + var position = 0; + + $('.type').each(function () { + var input = $(this); + var tab = input.closest(".tab-container").data("tab"); + var card = input.closest(".card-container").data("card"); + //input = input.next(); + var postab = tab !== "" ? position + "#" + tab : position + ""; + postab += (card) && card !== "" ? "%" + card : ""; + reAssignIdName(input, position); // type + + input = input.next(); + reAssignIdName(input, position); // differentiator + + input = input.next(); + reAssignIdName(input, position); // zone + + input = input.next(); + reAssignIdName(input, position); // position + + input.val(postab); + position++; + }); + }; + + var reAssignIdName = function (input, pos) { + var name = input.attr('name'); + input.attr('name', name.replace(new RegExp("\\[.*\\]", 'gi'), '[' + pos + ']')); + + var id = input.attr('id'); + input.attr('id', id.replace(new RegExp('_.*__', 'i'), '_' + pos + '__')); + }; + + var startPos; + + // Makes sortable Cards and Shapes + function initTab() { + $(".tabdrag").sortable({ + placeholder: "placement-placeholder", + connectWith: ".tabdrag", + stop: function (event, ui) { + assignPositions(); + $('#save-message').show(); + } + }); + $(".carddrag").sortable({ + placeholder: "placement-placeholder", + connectWith: ".carddrag", + stop: function (event, ui) { + assignPositions(); + $('#save-message').show(); + } + }); + } + + // Makes sortable tabs + $('#sortableTabs').sortable({ + placeholder: "tab-placeholder", + stop: function (event, ui) { + assignPositions(); + $('#save-message').show(); + } + }); + + $("#newTab").click(function (e) { + e.preventDefault(); + // get the new tab name, cancel if blank + var tab = $("#tabName").val().replace(/\s/g, ""); + if (!tab.length) { + return; + } + + if (tab.toLowerCase() === "content") { + $("#tabName").val(""); + return; + } + + // in tabs already + var tabs = getTabs(true); + if ($.inArray(tab, tabs) >= 0) { + $("#tabName").val(""); + return; + } + //Insert the tab with an empty card + $("#sortableTabs").append('

    Delete' + + tab + '

      ' + + '
    • ' + + '
      • ' + + '
      ' + ); + // make it sortable + initTab(); + $("#sortableTabs").sortable("refresh"); + // clear the textbox + $("#tabName").val(""); + }); + + $("#newCard").click(function (e) { + e.preventDefault(); + // get the new tab name, cancel if blank + var card = $("#tabName").val().replace(/\s/g, ""); + if (!card.length) { + return; + } + // insert card in the Content Tab + $("#content-tab > ul").append('
    • Delete

      ' + + card + '

      • '); + // make it sortable + initTab(); + $("#sortableTabs").sortable("refresh"); + // clear the textbox + $("#tabName").val(""); + }); + // remove tabs + // append items to content, create content if not there + $("#placement").on("click", ".delete", function (e) { + var me = $(this); + var parent = me.parent(".zone-container"); + if (!parent.length) { + parent = me.parents(".zone-container"); + } + var list, newList; + if (parent.hasClass("tab-container")) { + list = parent.children(".tabdrag").html(); + newList = $("#placement .tabdrag").first(); + } else if (parent.hasClass("card-container")) { + list = parent.children(".carddrag").html(); + newList = $("#placement .tabdrag").first(); + } + // get first tab + if (newList.length) { + parent.remove(); + newList.append(list); + } + assignPositions(); + // make it sortable + initTab(); + }); + + // toggle editor shapes + $("#placement").on("click", ".toggle", function (e) { + var $this = $(this); + var shape = $(this).next().next(); + shape.toggle(); + + if ($this.text() === $this.data("text-show")) { + $this.text($this.data("text-hide")); + } else { + $this.text($this.data("text-show")); + } + }); + + // returns all the tabs + function getTabs(header) { + var tabs = []; + $(".zone-container").each(function (index, e) { + tabs.push($(e).data("tab")); + }); + + return tabs; + } + + initTab(); + assignPositions(); + $('.shape-editor *').attr('disabled', 'disabled'); + $("#placement").disableSelection(); +})(jQuery); \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/ContentTypePlacementStrategy.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/ContentTypePlacementStrategy.cs index 374da309ac4..a1091c30d2b 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/ContentTypePlacementStrategy.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/ContentTypePlacementStrategy.cs @@ -7,6 +7,7 @@ using Orchard.ContentTypes.Extensions; using Orchard.Environment; using Orchard.Environment.Extensions.Models; +using Orchard.UI.Admin; namespace Orchard.ContentTypes.Services { public class TypePlacement { @@ -16,9 +17,12 @@ public class TypePlacement { public class ContentTypePlacementStrategy : IShapeTableEventHandler { private readonly Work _contentDefinitionManager; + private readonly IWorkContextAccessor _workContextAccessor; - public ContentTypePlacementStrategy(Work contentDefinitionManager) { + public ContentTypePlacementStrategy(Work contentDefinitionManager, + IWorkContextAccessor workContextAccessor) { _contentDefinitionManager = contentDefinitionManager; + _workContextAccessor = workContextAccessor; } public virtual Feature Feature { get; set; } @@ -29,7 +33,7 @@ public void ShapeTableCreated(ShapeTable shapeTable) { var allPlacements = typeDefinitions.SelectMany(td => td.GetPlacement(PlacementType.Editor).Select(p => new TypePlacement { Placement = p, ContentType = td.Name }) ); // group all placement settings by shape type - var shapePlacements = allPlacements.GroupBy(x => x.Placement.ShapeType).ToDictionary(x => x.Key, y=> y.ToList()); + var shapePlacements = allPlacements.GroupBy(x => x.Placement.ShapeType).ToDictionary(x => x.Key, y=> y.ToList(), StringComparer.OrdinalIgnoreCase); // create a new predicate in a ShapeTableDescriptor has a custom placement foreach(var shapeType in shapeTable.Descriptors.Keys) { @@ -44,8 +48,11 @@ public void ShapeTableCreated(ShapeTable shapeTable) { } descriptor.Placement = ctx => { - if(ctx.DisplayType == null) { - foreach(var customPlacement in customPlacements) { + var workContext = _workContextAccessor.GetContext(); + if (ctx.DisplayType == null && + AdminFilter.IsApplied(workContext.HttpContext.Request.RequestContext)) { // Tests if it's executing in admin in order to override placement.info for editors in back-end only + + foreach (var customPlacement in customPlacements) { var type = customPlacement.ContentType; var differentiator = customPlacement.Placement.Differentiator; @@ -56,8 +63,14 @@ public void ShapeTableCreated(ShapeTable shapeTable) { if (!String.IsNullOrEmpty(customPlacement.Placement.Position)) { location = String.Concat(location, ":", customPlacement.Placement.Position); } - - return new PlacementInfo { Location = location }; + // clone the identified Placement.info into a new one in order to keep original informations like Wrappers and Alternates + var originalPlacementInfo = placement(ctx); + return new PlacementInfo { + Location = location, + Alternates = originalPlacementInfo.Alternates, + ShapeType = originalPlacementInfo.ShapeType, + Wrappers = originalPlacementInfo.Wrappers + }; } } } @@ -68,4 +81,4 @@ public void ShapeTableCreated(ShapeTable shapeTable) { } } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/PlacementService.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/PlacementService.cs index 78b60cb2883..cd500bfa800 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/PlacementService.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/PlacementService.cs @@ -18,6 +18,7 @@ namespace Orchard.ContentTypes.Services { public class DriverResultPlacement { + public PlacementInfo PlacementInfo { get; set; } public PlacementSettings PlacementSettings { get; set; } public DriverResult ShapeResult { get; set; } public dynamic Shape { get; set; } @@ -201,6 +202,7 @@ private IEnumerable ExtractPlacement(DriverResult result, yield return new DriverResultPlacement { + PlacementInfo = placement, Shape = itemShape.Content, ShapeResult = contentShapeResult, PlacementSettings = new PlacementSettings { diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Styles/orchard-contenttypes-admin.css b/src/Orchard.Web/Modules/Orchard.ContentTypes/Styles/orchard-contenttypes-admin.css index e8599792792..0718352c049 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Styles/orchard-contenttypes-admin.css +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Styles/orchard-contenttypes-admin.css @@ -21,38 +21,38 @@ .manage-part, .manage-field { margin-bottom: 0; - padding:0; + padding: 0; border-bottom: 1px solid #EAEAEA; } -.manage-part h3, -.manage-field h3 { - display: relative; - line-height: 1.4em; - padding-bottom: 0; - padding-top: 0; -} + .manage-part h3, + .manage-field h3 { + display: relative; + line-height: 1.4em; + padding-bottom: 0; + padding-top: 0; + } -.manage-part h3, -.manage-field h3, -.manage-part h4, -.manage-type .manage-field .details, -.manage-type .manage-part .manage-field, -.manage-type .manage-part .settings { - padding-left: 30px; - padding-right: 30px; -} + .manage-part h3, + .manage-field h3, + .manage-part h4, + .manage-type .manage-field .details, + .manage-type .manage-part .manage-field, + .manage-type .manage-part .settings { + padding-left: 30px; + padding-right: 30px; + } -.manage-part h3, .manage-field h3 { - margin: 1em 0 !important; - padding-left: 30px; - width: 90%; -} + .manage-part h3, .manage-field h3 { + margin: 1em 0 !important; + padding-left: 30px; + width: 90%; + } -.manage-part .expando-glyph, .manage-field .expando-glyph { - width:16px; - height:16px; -} + .manage-part .expando-glyph, .manage-field .expando-glyph { + width: 16px; + height: 16px; + } .manage-type .manage-field .settings { padding-bottom: 10px; @@ -176,38 +176,90 @@ fieldset.action { /* PLACEMENT EDITOR */ +.tabdrag, .carddrag { + min-height: 20px; +} -#placement li { +.zone-container { + border: 1px dotted #6F6F6F; + padding: 10px; margin-bottom: 10px; - padding: 0px; - border: 1px solid #eee; } - #placement li .shape-type { - cursor: move; - background-color: #eee; - background: #EEE url(images/move.gif) no-repeat 10px 15px; - height: 30px; - padding: 10px 0px 0px 30px; + .zone-container li { + margin-bottom: 10px; + padding: 0px; + border: 1px solid #eee; } - #placement li .shape-editor { - padding: 10px; - background: white; - } +#placement .zone-container h2 { + cursor: move; + margin-top: 0px; + padding-left: 20px; + padding-bottom: 15px; +} + +#placement .tab-container { + background: white url(images/move.gif) no-repeat 10px 15px; +} + +.zone-container li .shape-type { + cursor: move; + background-color: #eee; + background: #EEE url(images/move.gif) no-repeat 10px 10px; + height: 30px; + padding: 5px 0px 0px 30px; +} + +.zone-container li .card-type { + cursor: move; + background-color: #ccc; + background: #ccc url(images/move.gif) no-repeat 10px 10px; + height: 30px; + padding: 5px 10px 5px 30px; + margin-bottom: 10px; +} + +#placement #content-tab { + cursor: default; +} + +.zone-container li .toggle { + float: right; + padding-top: 5px; + padding-right: 5px; + cursor: pointer; +} + +.zone-container li .shape-editor { + padding: 10px; + background: white; + display: none; +} #save-message { display: none; margin-bottom: 10px; } -#placement fieldset { +.zone-container fieldset { float: inherit; /* prevent bad layout if float is defined to left in specific parts, e.g. datetimepicker */ height: auto; } -.placement-placeholder { +.tab-placeholder { background: #FDF5BC; border: 1px solid #FDF5BC; height: 100px; } + +.placement-placeholder { + background: #FDF5BC; + border: 1px solid #FDF5BC; + height: 40px; +} + +.zone-container .delete { + float: right; + cursor: pointer; +} diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditPartFieldViewModel.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditPartFieldViewModel.cs index e57cba1cfcd..18707f8302d 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditPartFieldViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditPartFieldViewModel.cs @@ -19,7 +19,7 @@ public EditPartFieldViewModel(int index, ContentPartFieldDefinition field) { } public int Index { get; set; } - public string Prefix { get { return "Fields[" + Index + "]"; } } + public string Prefix { get { return "Fields[" + Name + "]"; } } public EditPartViewModel Part { get; set; } public string Name { get; set; } @@ -29,4 +29,4 @@ public EditPartFieldViewModel(int index, ContentPartFieldDefinition field) { public SettingsDictionary Settings { get; set; } public ContentPartFieldDefinition _Definition { get; private set; } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditPlacementViewModel.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditPlacementViewModel.cs index ebc3df44e0f..596435dac48 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditPlacementViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditPlacementViewModel.cs @@ -6,7 +6,20 @@ namespace Orchard.ContentTypes.ViewModels { public class EditPlacementViewModel { public ContentTypeDefinition ContentTypeDefinition { get; set; } - public PlacementSettings[] PlacementSettings { get; set; } public List AllPlacements { get; set; } + public List Tabs { get; set; } + public Tab Content { get; set; } + } + + public class Tab { + public string Name { get; set; } + public List Cards { get; set; } + } + + public class Card { + public string Name { get; set; } + public string TabName { get; set; } + public List Placements { get; set; } + } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditTypePartViewModel.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditTypePartViewModel.cs index 324dce6bd66..4d21f83fe33 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditTypePartViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/EditTypePartViewModel.cs @@ -17,7 +17,7 @@ public EditTypePartViewModel(int index, ContentTypePartDefinition part) { } public int Index { get; set; } - public string Prefix { get { return "Parts[" + Index + "]"; } } + public string Prefix { get { return "Parts[" + PartDefinition.Name + "]"; } } public EditPartViewModel PartDefinition { get; set; } public SettingsDictionary PartSettings { get; set; } public SettingsDictionary Settings { get; set; } @@ -29,4 +29,4 @@ public string Description { get { return PartSettings.ContainsKey("ContentPartSettings.Description") ? PartSettings["ContentPartSettings.Description"] : null; } } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/ListContentsViewModel.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/ListContentsViewModel.cs deleted file mode 100644 index d9226a72302..00000000000 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/ViewModels/ListContentsViewModel.cs +++ /dev/null @@ -1,16 +0,0 @@ -//using System.Collections.Generic; -//using Orchard.ContentManagement; - -//namespace Orchard.ContentTypes.ViewModels { -// public class ListContentsViewModel { -// public string Id { get; set; } -// public int? Page { get; set; } -// public IList Entries { get; set; } - -// public class Entry { -// public ContentItem ContentItem { get; set; } -// public ContentItemMetadata ContentItemMetadata { get; set; } -// public ContentItemViewModel ViewModel { get; set; } -// } -// } -//} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/AddFieldTo.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/AddFieldTo.cshtml index d54b645d330..1e8eb98b47b 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/AddFieldTo.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/AddFieldTo.cshtml @@ -1,9 +1,11 @@ @using Orchard.Utility.Extensions + @model Orchard.ContentTypes.ViewModels.AddFieldViewModel + @{ Style.Require("ContentTypesAdmin"); - Layout.Title = T("Add New Field To \"{0}\"", Model.Part.DisplayName).ToString(); + Layout.Title = T("Add New Field To \"{0}\"", Html.Raw(Model.Part.DisplayName)).Text; var returnUrl = Request.QueryString["returnUrl"]; } @@ -31,48 +33,48 @@ } @using(Script.Foot()){ - + $displayName.keyup(compute); + $displayName.blur(compute); + }) + //]]> + } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/AddPartsTo.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/AddPartsTo.cshtml index 3f1f868bfe8..bd1649831bb 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/AddPartsTo.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/AddPartsTo.cshtml @@ -1,9 +1,12 @@ @model Orchard.ContentTypes.ViewModels.AddPartsViewModel + @{ Style.Require("ContentTypesAdmin"); - Layout.Title = T("Add Parts To \"{0}\"", Model.Type.DisplayName).ToString(); + Layout.Title = T("Add Parts To \"{0}\"", Html.Raw(Model.Type.DisplayName)).Text; } + @T("Choose the Parts to add to this Content Type.") + @using (Html.BeginFormAntiForgeryPost()) { @Html.ValidationSummary()
        diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/Create.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/Create.cshtml index b410b9072e8..99b27ab7ba3 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/Create.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/Create.cshtml @@ -1,6 +1,8 @@ @model Orchard.ContentTypes.ViewModels.CreateTypeViewModel -@{ Layout.Title = T("New Content Type").ToString(); } +@{ + Layout.Title = T("New Content Type").Text; +} @using (Html.BeginFormAntiForgeryPost()) { @Html.ValidationSummary() @@ -14,48 +16,49 @@
        -
        } +
        +} @using(Script.Foot()){ - + $displayName.keyup(compute); + $displayName.blur(compute); + }) + //]]> + } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/CreatePart.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/CreatePart.cshtml index 9430e4c247f..1e6290aa060 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/CreatePart.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/CreatePart.cshtml @@ -1,6 +1,8 @@ @model Orchard.ContentTypes.ViewModels.CreatePartViewModel -@{ Layout.Title = T("New Content Part").ToString(); } +@{ + Layout.Title = T("New Content Part").Text; +} @using (Html.BeginFormAntiForgeryPost()) { @Html.ValidationSummary() @@ -11,4 +13,5 @@
        -
        } \ No newline at end of file +
        +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/Edit.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/Edit.cshtml index bc0b6868a8f..de586853df1 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/Edit.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/Edit.cshtml @@ -1,10 +1,10 @@ -@using Orchard.Utility.Extensions; @model Orchard.ContentTypes.ViewModels.EditTypeViewModel + @{ Style.Require("ContentTypesAdmin"); Script.Require("jQuery"); Layout.Title = T("Edit Content Type - {0}", Html.Raw(Model.DisplayName)).Text; - var returnUrl = ViewContext.RequestContext.HttpContext.Request.ToUrlString(); + var returnUrl = ViewContext.RequestContext.HttpContext.Request.RawUrl; }
        @@ -45,13 +45,13 @@
        } -@using(Script.Foot()){ - +@using(Script.Foot()) { + } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditField.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditField.cshtml index 1ecb517d408..c259852d74c 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditField.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditField.cshtml @@ -1,22 +1,25 @@ @using Orchard.Utility.Extensions + @model Orchard.ContentTypes.ViewModels.EditFieldNameViewModel + @{ Style.Require("ContentTypesAdmin"); - Layout.Title = T("Edit Field \"{0}\"", Html.Raw(Model.DisplayName)).ToString(); + Layout.Title = T("Edit Content Field - {0}", Html.Raw(Model.DisplayName)).Text; var returnUrl = Request.QueryString["returnUrl"]; } @using (Html.BeginFormAntiForgeryPost()) { @Html.ValidationSummary() -
        - - @Html.TextBoxFor(m => m.DisplayName, new {@class = "text medium", autofocus = "autofocus"}) - @T("Name of the field as it will be displayed in screens.") - - @Html.HiddenFor(m => m.Name) -
        +
        + + @Html.TextBoxFor(m => m.DisplayName, new { @class = "text medium", autofocus = "autofocus" }) + @T("Name of the field as it will be displayed in screens.") + @T("Content Field Id: {0}", Model.Name) + + @Html.HiddenFor(m => m.Name) +
        @if (!String.IsNullOrWhiteSpace(returnUrl) && Request.IsLocalUrl(returnUrl)) { diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditPart.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditPart.cshtml index 1794d419ad5..4b4e484d314 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditPart.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditPart.cshtml @@ -1,8 +1,9 @@ @model Orchard.ContentTypes.ViewModels.EditPartViewModel + @{ Style.Require("ContentTypesAdmin"); Script.Require("jQuery"); - Layout.Title = T("Edit Part").ToString(); + Layout.Title = T("Edit Content Part - {0}", Html.Raw(Model.DisplayName)).Text; } @using (Html.BeginFormAntiForgeryPost()) { @@ -28,12 +29,12 @@ } @using(Script.Foot()){ - + } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditPlacement.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditPlacement.cshtml index 93c054a0285..9bc902c0471 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditPlacement.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditPlacement.cshtml @@ -1,107 +1,98 @@ +@using Orchard.ContentTypes.Services +@using Orchard.ContentTypes.ViewModels + @model Orchard.ContentTypes.ViewModels.EditPlacementViewModel + @{ Style.Require("ContentTypesAdmin"); - Script.Require("jQueryUI_Sortable"); - Layout.Title = T("Edit Placement - {0}", Model.ContentTypeDefinition.DisplayName).ToString(); + Script.Require("PlacementEditor").AtFoot(); + Layout.Title = T("Edit Placement - {0}", Html.Raw(Model.ContentTypeDefinition.DisplayName)).Text; - var hiddenShapes = Model.AllPlacements.Where(x => String.IsNullOrEmpty(x.PlacementSettings.Zone) && (String.IsNullOrWhiteSpace(x.PlacementSettings.Position) || x.PlacementSettings.Position == "-")); +} +@functions +{ + private int i = 0; +} +@helper RenderPlacement(DriverResultPlacement p) { + var placement = p.PlacementSettings; + +
      • + @T("Show Editor Shape") +

        @placement.ShapeType @placement.Differentiator

        +
        + @try { + @Display(p.Shape) + } + catch { + } +
        + + @Html.HiddenFor(m => m.AllPlacements[i].PlacementSettings.ShapeType, new { @class = "type" }) + @Html.HiddenFor(m => m.AllPlacements[i].PlacementSettings.Differentiator, new { @class = "differentiator" }) + @Html.HiddenFor(m => m.AllPlacements[i].PlacementSettings.Zone, new { @class = "zone" }) + @Html.HiddenFor(m => m.AllPlacements[i].PlacementSettings.Position, new { @class = "position" }) +
      • + { + i++; + } } -
        @T("You need to hit \"Save\" in order to save your changes.")
        +@helper RenderCard(Card card) { +
      • + @if (!string.IsNullOrWhiteSpace(card.Name)) { + @T("Delete") +

        @card.Name

        + } +
          + @foreach (var p in card.Placements) { + @RenderPlacement(p); + } +
        +
      • +} +
        @T("You need to hit \"Save\" in order to save your changes.")
        +@* Alert messages *@ +
        +
        +

        @T("Nested cards are not allowed.")

        +
        +
        @using (Html.BeginFormAntiForgeryPost()) { @Html.ValidationSummary() +
        +
        +

        @T("Content")

        +
          + @foreach (var c in Model.Content.Cards) { + @RenderCard(c); + } +
        +
        + +
        + @foreach (var tab in Model.Tabs) { +
        + @T("Delete") +

        @tab.Name

        +
          + @foreach (var c in tab.Cards) { + @RenderCard(c); + } +
        +
        + } +
        +
        +
        + + + +
        -
          - @for (int i = 0; i < Model.AllPlacements.Count; i++ ) { - - var placement = Model.AllPlacements[i].PlacementSettings; - - if(placement.Zone != "Content") { - continue; - } - -
        • -

          @placement.ShapeType @placement.Differentiator

          -
          - @try { - @Display(Model.AllPlacements[i].Shape) - } - catch { - } -
          - - @* @shape.Position @(Model.PlacementSettings.Any(x => x.Equals(shape)))*@ - @Html.HiddenFor(m => m.AllPlacements[i].PlacementSettings.ShapeType, new { @class = "type" }) - @Html.HiddenFor(m => m.AllPlacements[i].PlacementSettings.Differentiator, new { @class = "differentiator" }) - @Html.HiddenFor(m => m.AllPlacements[i].PlacementSettings.Zone, new { @class = "zone" }) - @Html.HiddenFor(m => m.AllPlacements[i].PlacementSettings.Position, new { @class = "position" }) -
        • - } -
        -
        - -} - -@using (Script.Foot()) { - } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/List.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/List.cshtml index ffdd61d549c..80da8edd889 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/List.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/List.cshtml @@ -1,22 +1,25 @@ @model Orchard.ContentTypes.ViewModels.ListContentTypesViewModel + @{ Style.Require("ContentTypesAdmin"); Script.Require("jQuery"); Script.Include("admin-contenttypes.js"); - Layout.Title = T("Manage Content Types").ToString(); + Layout.Title = T("Manage Content Types").Text; }
        - @Html.ActionLink(T("Create new type").ToString(), "Create", new{Controller="Admin",Area="Orchard.ContentTypes"}, new { @class = "button primaryAction" }) + @Html.ActionLink(T("Create new type").Text, "Create", new { Controller = "Admin", Area = "Orchard.ContentTypes" }, new { @class = "button primaryAction" })
        +
        +
          @foreach (var type in Model.Types) { -
        • - @Html.DisplayFor(m => type) -
        • +
        • + @Html.DisplayFor(m => type) +
        • }
        \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/ListParts.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/ListParts.cshtml index a3f03a301af..f3a072c90f3 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/ListParts.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/ListParts.cshtml @@ -1,20 +1,25 @@ @model Orchard.ContentTypes.ViewModels.ListContentPartsViewModel + @{ Script.Require("jQuery"); Script.Include("admin-contenttypes.js"); - Layout.Title = T("Content Parts").ToString(); + Layout.Title = T("Content Parts").Text; + } +
        - @Html.ActionLink(T("Create new part").ToString(), "CreatePart", new{Controller="Admin",Area="Orchard.ContentTypes"}, new { @class = "button primaryAction" }) + @Html.ActionLink(T("Create new part").Text, "CreatePart", new { Controller = "Admin", Area = "Orchard.ContentTypes" }, new { @class = "button primaryAction" })
        +
        +
          @foreach (var type in Model.Parts) { -
        • - @Html.DisplayFor(m => type) -
        • +
        • + @Html.DisplayFor(m => type) +
        • }
        diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/RemoveFieldFrom.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/RemoveFieldFrom.cshtml index c2a94834b82..89c5834b11d 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/RemoveFieldFrom.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/RemoveFieldFrom.cshtml @@ -1,7 +1,8 @@ @model Orchard.ContentTypes.ViewModels.RemoveFieldViewModel + @{ Style.Require("ContentTypesAdmin"); - Layout.Title = T("Remove the \"{0}\" part from \"{1}\"", Model.Name, Model.Part.DisplayName).ToString(); + Layout.Title = T("Remove the \"{0}\" Content Field from \"{1}\"", Model.Name, Html.Raw(Model.Part.DisplayName)).Text; } @using (Html.BeginFormAntiForgeryPost()) { diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/RemovePartFrom.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/RemovePartFrom.cshtml index fc0f26550da..0b275e634f1 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/RemovePartFrom.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/RemovePartFrom.cshtml @@ -1,7 +1,8 @@ @model Orchard.ContentTypes.ViewModels.RemovePartViewModel + @{ Style.Require("ContentTypesAdmin"); - Layout.Title = T("Remove the \"{0}\" part from \"{1}\"", Model.Name, Model.Type.DisplayName).ToString(); + Layout.Title = T("Remove the \"{0}\" Content Part from \"{1}\"", Model.Name, Html.Raw(Model.Type.DisplayName)).Text; } @using (Html.BeginFormAntiForgeryPost()) { diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DefinitionTemplates/ContentTypeSettingsViewModel.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DefinitionTemplates/ContentTypeSettingsViewModel.cshtml index d245600f78e..adfaee84ba5 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DefinitionTemplates/ContentTypeSettingsViewModel.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DefinitionTemplates/ContentTypeSettingsViewModel.cshtml @@ -4,7 +4,7 @@ @Html.EditorFor(m => m.Creatable) @Html.ValidationMessageFor(m => m.Creatable) - @T("Determines if an instance of this content type can be created through the UI.") + @T("Determines if this type is listed among the types creatable through the UI. This setting doesn't affect security.")
        diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DisplayTemplates/EditPartViewModel.cshtml b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DisplayTemplates/EditPartViewModel.cshtml index ecadf6a531f..6164e6fe727 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DisplayTemplates/EditPartViewModel.cshtml +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Views/DisplayTemplates/EditPartViewModel.cshtml @@ -2,7 +2,7 @@

        @Model.DisplayName

        - @if(!string.IsNullOrWhiteSpace(Model.Description)) {@T(Model.Description)} + @if(!string.IsNullOrWhiteSpace(Model.Description)) {@T(Html.Encode(Model.Description))}
        \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.CustomForms/Views/Item/Create.cshtml b/src/Orchard.Web/Modules/Orchard.CustomForms/Views/Item/Create.cshtml index 72365658ab1..2d569380273 100644 --- a/src/Orchard.Web/Modules/Orchard.CustomForms/Views/Item/Create.cshtml +++ b/src/Orchard.Web/Modules/Orchard.CustomForms/Views/Item/Create.cshtml @@ -1,7 +1,13 @@ @using Orchard.ContentManagement @using Orchard.Utility.Extensions @using Orchard.ContentManagement.Aspects; +@using Orchard.ContentManagement.MetaData; +@using Orchard.ContentManagement.MetaData.Models; +@using Orchard.Core.Contents.Settings; + @{ + IContentDefinitionManager _contentDefinitionManager = WorkContext.Resolve(); + ContentItem customForm = Model.ContentItem; string returnUrl = Model.ReturnUrl; var metadata = customForm.ContentManager.GetItemMetadata(customForm); @@ -13,6 +19,19 @@ Model.Zones["Sidebar"].Items.Clear(); var submitButtonText = String.IsNullOrEmpty(Model.ContentItem.CustomFormPart.SubmitButtonText) ? T("Submit").Text : Model.ContentItem.CustomFormPart.SubmitButtonText; + var publishButtonText = String.IsNullOrEmpty(Model.ContentItem.CustomFormPart.PublishButtonText) ? T("Publish").Text : Model.ContentItem.CustomFormPart.PublishButtonText; + + var showPublishButton = Model.ContentItem.CustomFormPart.SavePublishContentItem; + // Read type definition to check if content is draftable + var typeDefinition = _contentDefinitionManager + .ListTypeDefinitions() + .Where(x => String.Equals(x.Name, Model.ContentItem.CustomFormPart.ContentType, StringComparison.OrdinalIgnoreCase)) + .FirstOrDefault(); + if (typeDefinition != null) { + // Publish button has to be visible only if content is draftable AND is set to show the publish button + showPublishButton = showPublishButton && + typeDefinition.Settings.GetModel().Draftable; + } } @Display(New.Parts_Title().Title(displayText)) @@ -22,8 +41,28 @@ // Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type @Display(Model) + @Html.Hidden("contentId", (int)Model.ContentId, new { id = string.Empty }); +
        - + @if (Model.ContentItem.CustomFormPart.SavePublishContentItem == false || Model.ContentItem.CustomFormPart.SaveContentItem == true) { + + } + @if (showPublishButton) { + + }
        -} + +
        + @if (Model.Actions != null) { +
        + @Display(Model.Actions) +
        + } + @if (Model.Sidebar != null) { +
        + @Display(Model.Sidebar) +
        + } +
        +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.CustomForms/Views/Parts.CustomForm.Wrapper.cshtml b/src/Orchard.Web/Modules/Orchard.CustomForms/Views/Parts.CustomForm.Wrapper.cshtml index ec6039a281a..ee78a66f968 100644 --- a/src/Orchard.Web/Modules/Orchard.CustomForms/Views/Parts.CustomForm.Wrapper.cshtml +++ b/src/Orchard.Web/Modules/Orchard.CustomForms/Views/Parts.CustomForm.Wrapper.cshtml @@ -1,22 +1,46 @@ -@{ +@using Orchard.ContentManagement.MetaData; +@using Orchard.ContentManagement.MetaData.Models; +@using Orchard.Core.Contents.Settings; + +@{ + IContentDefinitionManager _contentDefinitionManager = WorkContext.Resolve(); + dynamic editor = Model.Editor; - + if (TempData.ContainsKey("CustomFormWidget.InvalidCustomFormState")) { editor = TempData["CustomFormWidget.InvalidCustomFormState"]; } - + // remove default Save/Publish buttons editor.Zones["Sidebar"].Items.Clear(); + + var showPublishButton = Model.ContentItem.CustomFormPart.SavePublishContentItem; + + // Read type definition to check if content is draftable + var typeDefinition = _contentDefinitionManager + .ListTypeDefinitions() + .Where(x => String.Equals(x.Name, Model.ContentItem.CustomFormPart.ContentType, StringComparison.OrdinalIgnoreCase)) + .FirstOrDefault(); + if (typeDefinition != null) { + // Publish button has to be visible only if content is draftable AND is set to show the publish button + showPublishButton = showPublishButton && + typeDefinition.Settings.GetModel().Draftable; + } } @using (Html.BeginFormAntiForgeryPost(Url.Action("Create", "Item", new { area = "Orchard.CustomForms", id = Model.ContentItem.Id }))) { - @Html.ValidationSummary() +@Html.ValidationSummary() // Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type - @Display(editor) +@Display(editor) - @Html.Hidden("returnUrl", Request.RawUrl, new { id = string.Empty }); +@Html.Hidden("returnUrl", Request.RawUrl, new { id = string.Empty }); +@Html.Hidden("contentId", !string.IsNullOrWhiteSpace(Request.QueryString["contentId"]) ? Request.QueryString["contentId"] : "0", new { id = string.Empty }); -
        - -
        -} +
        + + + @if (showPublishButton) { + + } +
        +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.CustomForms/Web.config b/src/Orchard.Web/Modules/Orchard.CustomForms/Web.config index a3cb5df907e..baf3b31252b 100644 --- a/src/Orchard.Web/Modules/Orchard.CustomForms/Web.config +++ b/src/Orchard.Web/Modules/Orchard.CustomForms/Web.config @@ -7,7 +7,7 @@ - + @@ -21,39 +21,58 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.CustomForms/packages.config b/src/Orchard.Web/Modules/Orchard.CustomForms/packages.config index 6729ced4977..1c55d6960bb 100644 --- a/src/Orchard.Web/Modules/Orchard.CustomForms/packages.config +++ b/src/Orchard.Web/Modules/Orchard.CustomForms/packages.config @@ -1,7 +1,8 @@  - - - - - \ No newline at end of file + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Dashboards/Module.txt b/src/Orchard.Web/Modules/Orchard.Dashboards/Module.txt index c89dddb232a..c116003e5c5 100644 --- a/src/Orchard.Web/Modules/Orchard.Dashboards/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Dashboards/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: The Dashboards module enables administrators to customize the dashboard screen of the administration UI of the application. Features: Orchard.Dashboards: diff --git a/src/Orchard.Web/Modules/Orchard.Dashboards/Orchard.Dashboards.csproj b/src/Orchard.Web/Modules/Orchard.Dashboards/Orchard.Dashboards.csproj index c426b514352..261c2bde397 100644 --- a/src/Orchard.Web/Modules/Orchard.Dashboards/Orchard.Dashboards.csproj +++ b/src/Orchard.Web/Modules/Orchard.Dashboards/Orchard.Dashboards.csproj @@ -12,8 +12,8 @@ Properties Orchard.Dashboards Orchard.Dashboards - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -25,6 +25,9 @@ + + +
        true @@ -34,7 +37,7 @@ DEBUG;TRACE prompt 4 - AllRules.ruleset + ..\..\..\OrchardBasicCorrectness.ruleset false @@ -48,10 +51,12 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -63,29 +68,23 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -93,8 +92,6 @@ - - @@ -116,17 +113,17 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {6bd8b2fa-f2e3-4ac8-a4c3-2925a653889a} Orchard.Layouts - False + $(MvcBuildViews) @@ -146,7 +143,7 @@ - + 10.0 @@ -172,7 +169,7 @@ --> - + @@ -186,10 +183,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Dashboards/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Dashboards/Properties/AssemblyInfo.cs index da4339c40c8..50b39118c78 100644 --- a/src/Orchard.Web/Modules/Orchard.Dashboards/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Dashboards/Properties/AssemblyInfo.cs @@ -32,6 +32,6 @@ // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Dashboards/Routes.cs b/src/Orchard.Web/Modules/Orchard.Dashboards/Routes.cs index e370ddc6132..d9219bb7191 100644 --- a/src/Orchard.Web/Modules/Orchard.Dashboards/Routes.cs +++ b/src/Orchard.Web/Modules/Orchard.Dashboards/Routes.cs @@ -6,29 +6,25 @@ namespace Orchard.Dashboards { public class Routes : IRouteProvider { public void GetRoutes(ICollection routes) { - foreach (var routeDescriptor in GetRoutes()) - routes.Add(routeDescriptor); - } - - public IEnumerable GetRoutes() { - yield return new RouteDescriptor { - Priority = -4, - Route = new Route( - "Admin", - new RouteValueDictionary { - {"area", "Orchard.Dashboards"}, - {"controller", "Dashboard"}, - {"action", "Display"} - }, - new RouteValueDictionary(), - new RouteValueDictionary { - {"area", "Orchard.Dashboards"} - }, - new MvcRouteHandler()) - }; + var routeDescriptors = new[] { + new RouteDescriptor { + Priority = -4, + Route = new Route( + "Admin", + new RouteValueDictionary { + {"area", "Orchard.Dashboards"}, + {"controller", "Dashboard"}, + {"action", "Display"} + }, + new RouteValueDictionary(), + new RouteValueDictionary { + {"area", "Orchard.Dashboards"} + }, + new MvcRouteHandler()) + }, - yield return new RouteDescriptor { - Route = new Route( + new RouteDescriptor { + Route = new Route( "Admin/Dashboards/Settings", new RouteValueDictionary { {"area", "Orchard.Dashboards"}, @@ -40,10 +36,10 @@ public IEnumerable GetRoutes() { {"area", "Orchard.Dashboards"} }, new MvcRouteHandler()) - }; + }, - yield return new RouteDescriptor { - Route = new Route( + new RouteDescriptor { + Route = new Route( "Admin/Dashboards/List", new RouteValueDictionary { {"area", "Orchard.Dashboards"}, @@ -55,7 +51,11 @@ public IEnumerable GetRoutes() { {"area", "Orchard.Dashboards"} }, new MvcRouteHandler()) + } }; + + foreach (var routeDescriptor in routeDescriptors) + routes.Add(routeDescriptor); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Dashboards/Styles/bootstrap.css b/src/Orchard.Web/Modules/Orchard.Dashboards/Styles/bootstrap.css deleted file mode 100644 index 9d77ed40d88..00000000000 --- a/src/Orchard.Web/Modules/Orchard.Dashboards/Styles/bootstrap.css +++ /dev/null @@ -1,2199 +0,0 @@ -/*! - * Bootstrap v3.3.4 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ - -/*! - * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=6737c6372ebd005d9906) - * Config saved to config.json and https://gist.github.com/6737c6372ebd005d9906 - */ -/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ -html { - font-family: sans-serif; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; -} -body { - margin: 0; -} -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -main, -menu, -nav, -section, -summary { - display: block; -} -audio, -canvas, -progress, -video { - display: inline-block; - vertical-align: baseline; -} -audio:not([controls]) { - display: none; - height: 0; -} -[hidden], -template { - display: none; -} -a { - background-color: transparent; -} -a:active, -a:hover { - outline: 0; -} -abbr[title] { - border-bottom: 1px dotted; -} -b, -strong { - font-weight: bold; -} -dfn { - font-style: italic; -} -h1 { - font-size: 2em; - margin: 0.67em 0; -} -mark { - background: #ff0; - color: #000; -} -small { - font-size: 80%; -} -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} -sup { - top: -0.5em; -} -sub { - bottom: -0.25em; -} -img { - border: 0; -} -svg:not(:root) { - overflow: hidden; -} -figure { - margin: 1em 40px; -} -hr { - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; - box-sizing: content-box; - height: 0; -} -pre { - overflow: auto; -} -code, -kbd, -pre, -samp { - font-family: monospace, monospace; - font-size: 1em; -} -button, -input, -optgroup, -select, -textarea { - color: inherit; - font: inherit; - margin: 0; -} -button { - overflow: visible; -} -button, -select { - text-transform: none; -} -button, -html input[type="button"], -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; - cursor: pointer; -} -button[disabled], -html input[disabled] { - cursor: default; -} -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - padding: 0; -} -input { - line-height: normal; -} -input[type="checkbox"], -input[type="radio"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - padding: 0; -} -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { - height: auto; -} -input[type="search"] { - -webkit-appearance: textfield; - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; - box-sizing: content-box; -} -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; -} -legend { - border: 0; - padding: 0; -} -textarea { - overflow: auto; -} -optgroup { - font-weight: bold; -} -table { - border-collapse: collapse; - border-spacing: 0; -} -td, -th { - padding: 0; -} -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -*:before, -*:after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -html { - font-size: 10px; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -} -body { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - line-height: 1.42857143; - color: #333333; - background-color: #ffffff; -} -input, -button, -select, -textarea { - font-family: inherit; - font-size: inherit; - line-height: inherit; -} -a { - color: #337ab7; - text-decoration: none; -} -a:hover, -a:focus { - color: #23527c; - text-decoration: underline; -} -a:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -figure { - margin: 0; -} -img { - vertical-align: middle; -} -.img-responsive { - display: block; - max-width: 100%; - height: auto; -} -.img-rounded { - border-radius: 6px; -} -.img-thumbnail { - padding: 4px; - line-height: 1.42857143; - background-color: #ffffff; - border: 1px solid #dddddd; - border-radius: 4px; - -webkit-transition: all 0.2s ease-in-out; - -o-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; - display: inline-block; - max-width: 100%; - height: auto; -} -.img-circle { - border-radius: 50%; -} -hr { - margin-top: 20px; - margin-bottom: 20px; - border: 0; - border-top: 1px solid #eeeeee; -} -.sr-only { - position: absolute; - width: 1px; - height: 1px; - margin: -1px; - padding: 0; - overflow: hidden; - clip: rect(0, 0, 0, 0); - border: 0; -} -.sr-only-focusable:active, -.sr-only-focusable:focus { - position: static; - width: auto; - height: auto; - margin: 0; - overflow: visible; - clip: auto; -} -[role="button"] { - cursor: pointer; -} -h1, -h2, -h3, -h4, -h5, -h6, -.h1, -.h2, -.h3, -.h4, -.h5, -.h6 { - font-family: inherit; - font-weight: 500; - line-height: 1.1; - color: inherit; -} -h1 small, -h2 small, -h3 small, -h4 small, -h5 small, -h6 small, -.h1 small, -.h2 small, -.h3 small, -.h4 small, -.h5 small, -.h6 small, -h1 .small, -h2 .small, -h3 .small, -h4 .small, -h5 .small, -h6 .small, -.h1 .small, -.h2 .small, -.h3 .small, -.h4 .small, -.h5 .small, -.h6 .small { - font-weight: normal; - line-height: 1; - color: #777777; -} -h1, -.h1, -h2, -.h2, -h3, -.h3 { - margin-top: 20px; - margin-bottom: 10px; -} -h1 small, -.h1 small, -h2 small, -.h2 small, -h3 small, -.h3 small, -h1 .small, -.h1 .small, -h2 .small, -.h2 .small, -h3 .small, -.h3 .small { - font-size: 65%; -} -h4, -.h4, -h5, -.h5, -h6, -.h6 { - margin-top: 10px; - margin-bottom: 10px; -} -h4 small, -.h4 small, -h5 small, -.h5 small, -h6 small, -.h6 small, -h4 .small, -.h4 .small, -h5 .small, -.h5 .small, -h6 .small, -.h6 .small { - font-size: 75%; -} -h1, -.h1 { - font-size: 36px; -} -h2, -.h2 { - font-size: 30px; -} -h3, -.h3 { - font-size: 24px; -} -h4, -.h4 { - font-size: 18px; -} -h5, -.h5 { - font-size: 14px; -} -h6, -.h6 { - font-size: 12px; -} -p { - margin: 0 0 10px; -} -.lead { - margin-bottom: 20px; - font-size: 16px; - font-weight: 300; - line-height: 1.4; -} -@media (min-width: 768px) { - .lead { - font-size: 21px; - } -} -small, -.small { - font-size: 85%; -} -mark, -.mark { - background-color: #fcf8e3; - padding: .2em; -} -.text-left { - text-align: left; -} -.text-right { - text-align: right; -} -.text-center { - text-align: center; -} -.text-justify { - text-align: justify; -} -.text-nowrap { - white-space: nowrap; -} -.text-lowercase { - text-transform: lowercase; -} -.text-uppercase { - text-transform: uppercase; -} -.text-capitalize { - text-transform: capitalize; -} -.text-muted { - color: #777777; -} -.text-primary { - color: #337ab7; -} -a.text-primary:hover { - color: #286090; -} -.text-success { - color: #3c763d; -} -a.text-success:hover { - color: #2b542c; -} -.text-info { - color: #31708f; -} -a.text-info:hover { - color: #245269; -} -.text-warning { - color: #8a6d3b; -} -a.text-warning:hover { - color: #66512c; -} -.text-danger { - color: #a94442; -} -a.text-danger:hover { - color: #843534; -} -.bg-primary { - color: #fff; - background-color: #337ab7; -} -a.bg-primary:hover { - background-color: #286090; -} -.bg-success { - background-color: #dff0d8; -} -a.bg-success:hover { - background-color: #c1e2b3; -} -.bg-info { - background-color: #d9edf7; -} -a.bg-info:hover { - background-color: #afd9ee; -} -.bg-warning { - background-color: #fcf8e3; -} -a.bg-warning:hover { - background-color: #f7ecb5; -} -.bg-danger { - background-color: #f2dede; -} -a.bg-danger:hover { - background-color: #e4b9b9; -} -.page-header { - padding-bottom: 9px; - margin: 40px 0 20px; - border-bottom: 1px solid #eeeeee; -} -ul, -ol { - margin-top: 0; - margin-bottom: 10px; -} -ul ul, -ol ul, -ul ol, -ol ol { - margin-bottom: 0; -} -.list-unstyled { - padding-left: 0; - list-style: none; -} -.list-inline { - padding-left: 0; - list-style: none; - margin-left: -5px; -} -.list-inline > li { - display: inline-block; - padding-left: 5px; - padding-right: 5px; -} -dl { - margin-top: 0; - margin-bottom: 20px; -} -dt, -dd { - line-height: 1.42857143; -} -dt { - font-weight: bold; -} -dd { - margin-left: 0; -} -@media (min-width: 768px) { - .dl-horizontal dt { - float: left; - width: 160px; - clear: left; - text-align: right; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - .dl-horizontal dd { - margin-left: 180px; - } -} -abbr[title], -abbr[data-original-title] { - cursor: help; - border-bottom: 1px dotted #777777; -} -.initialism { - font-size: 90%; - text-transform: uppercase; -} -blockquote { - padding: 10px 20px; - margin: 0 0 20px; - font-size: 17.5px; - border-left: 5px solid #eeeeee; -} -blockquote p:last-child, -blockquote ul:last-child, -blockquote ol:last-child { - margin-bottom: 0; -} -blockquote footer, -blockquote small, -blockquote .small { - display: block; - font-size: 80%; - line-height: 1.42857143; - color: #777777; -} -blockquote footer:before, -blockquote small:before, -blockquote .small:before { - content: '\2014 \00A0'; -} -.blockquote-reverse, -blockquote.pull-right { - padding-right: 15px; - padding-left: 0; - border-right: 5px solid #eeeeee; - border-left: 0; - text-align: right; -} -.blockquote-reverse footer:before, -blockquote.pull-right footer:before, -.blockquote-reverse small:before, -blockquote.pull-right small:before, -.blockquote-reverse .small:before, -blockquote.pull-right .small:before { - content: ''; -} -.blockquote-reverse footer:after, -blockquote.pull-right footer:after, -.blockquote-reverse small:after, -blockquote.pull-right small:after, -.blockquote-reverse .small:after, -blockquote.pull-right .small:after { - content: '\00A0 \2014'; -} -address { - margin-bottom: 20px; - font-style: normal; - line-height: 1.42857143; -} -.container { - margin-right: auto; - margin-left: auto; - padding-left: 15px; - padding-right: 15px; -} -@media (min-width: 768px) { - .container { - width: 750px; - } -} -@media (min-width: 992px) { - .container { - width: 970px; - } -} -@media (min-width: 1200px) { - .container { - width: 1170px; - } -} -.container-fluid { - margin-right: auto; - margin-left: auto; - padding-left: 15px; - padding-right: 15px; -} -.row { - margin-left: -15px; - margin-right: -15px; -} -.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { - position: relative; - min-height: 1px; - padding-left: 15px; - padding-right: 15px; -} -.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { - float: left; -} -.col-xs-12 { - width: 100%; -} -.col-xs-11 { - width: 91.66666667%; -} -.col-xs-10 { - width: 83.33333333%; -} -.col-xs-9 { - width: 75%; -} -.col-xs-8 { - width: 66.66666667%; -} -.col-xs-7 { - width: 58.33333333%; -} -.col-xs-6 { - width: 50%; -} -.col-xs-5 { - width: 41.66666667%; -} -.col-xs-4 { - width: 33.33333333%; -} -.col-xs-3 { - width: 25%; -} -.col-xs-2 { - width: 16.66666667%; -} -.col-xs-1 { - width: 8.33333333%; -} -.col-xs-pull-12 { - right: 100%; -} -.col-xs-pull-11 { - right: 91.66666667%; -} -.col-xs-pull-10 { - right: 83.33333333%; -} -.col-xs-pull-9 { - right: 75%; -} -.col-xs-pull-8 { - right: 66.66666667%; -} -.col-xs-pull-7 { - right: 58.33333333%; -} -.col-xs-pull-6 { - right: 50%; -} -.col-xs-pull-5 { - right: 41.66666667%; -} -.col-xs-pull-4 { - right: 33.33333333%; -} -.col-xs-pull-3 { - right: 25%; -} -.col-xs-pull-2 { - right: 16.66666667%; -} -.col-xs-pull-1 { - right: 8.33333333%; -} -.col-xs-pull-0 { - right: auto; -} -.col-xs-push-12 { - left: 100%; -} -.col-xs-push-11 { - left: 91.66666667%; -} -.col-xs-push-10 { - left: 83.33333333%; -} -.col-xs-push-9 { - left: 75%; -} -.col-xs-push-8 { - left: 66.66666667%; -} -.col-xs-push-7 { - left: 58.33333333%; -} -.col-xs-push-6 { - left: 50%; -} -.col-xs-push-5 { - left: 41.66666667%; -} -.col-xs-push-4 { - left: 33.33333333%; -} -.col-xs-push-3 { - left: 25%; -} -.col-xs-push-2 { - left: 16.66666667%; -} -.col-xs-push-1 { - left: 8.33333333%; -} -.col-xs-push-0 { - left: auto; -} -.col-xs-offset-12 { - margin-left: 100%; -} -.col-xs-offset-11 { - margin-left: 91.66666667%; -} -.col-xs-offset-10 { - margin-left: 83.33333333%; -} -.col-xs-offset-9 { - margin-left: 75%; -} -.col-xs-offset-8 { - margin-left: 66.66666667%; -} -.col-xs-offset-7 { - margin-left: 58.33333333%; -} -.col-xs-offset-6 { - margin-left: 50%; -} -.col-xs-offset-5 { - margin-left: 41.66666667%; -} -.col-xs-offset-4 { - margin-left: 33.33333333%; -} -.col-xs-offset-3 { - margin-left: 25%; -} -.col-xs-offset-2 { - margin-left: 16.66666667%; -} -.col-xs-offset-1 { - margin-left: 8.33333333%; -} -.col-xs-offset-0 { - margin-left: 0%; -} -@media (min-width: 768px) { - .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 { - float: left; - } - .col-sm-12 { - width: 100%; - } - .col-sm-11 { - width: 91.66666667%; - } - .col-sm-10 { - width: 83.33333333%; - } - .col-sm-9 { - width: 75%; - } - .col-sm-8 { - width: 66.66666667%; - } - .col-sm-7 { - width: 58.33333333%; - } - .col-sm-6 { - width: 50%; - } - .col-sm-5 { - width: 41.66666667%; - } - .col-sm-4 { - width: 33.33333333%; - } - .col-sm-3 { - width: 25%; - } - .col-sm-2 { - width: 16.66666667%; - } - .col-sm-1 { - width: 8.33333333%; - } - .col-sm-pull-12 { - right: 100%; - } - .col-sm-pull-11 { - right: 91.66666667%; - } - .col-sm-pull-10 { - right: 83.33333333%; - } - .col-sm-pull-9 { - right: 75%; - } - .col-sm-pull-8 { - right: 66.66666667%; - } - .col-sm-pull-7 { - right: 58.33333333%; - } - .col-sm-pull-6 { - right: 50%; - } - .col-sm-pull-5 { - right: 41.66666667%; - } - .col-sm-pull-4 { - right: 33.33333333%; - } - .col-sm-pull-3 { - right: 25%; - } - .col-sm-pull-2 { - right: 16.66666667%; - } - .col-sm-pull-1 { - right: 8.33333333%; - } - .col-sm-pull-0 { - right: auto; - } - .col-sm-push-12 { - left: 100%; - } - .col-sm-push-11 { - left: 91.66666667%; - } - .col-sm-push-10 { - left: 83.33333333%; - } - .col-sm-push-9 { - left: 75%; - } - .col-sm-push-8 { - left: 66.66666667%; - } - .col-sm-push-7 { - left: 58.33333333%; - } - .col-sm-push-6 { - left: 50%; - } - .col-sm-push-5 { - left: 41.66666667%; - } - .col-sm-push-4 { - left: 33.33333333%; - } - .col-sm-push-3 { - left: 25%; - } - .col-sm-push-2 { - left: 16.66666667%; - } - .col-sm-push-1 { - left: 8.33333333%; - } - .col-sm-push-0 { - left: auto; - } - .col-sm-offset-12 { - margin-left: 100%; - } - .col-sm-offset-11 { - margin-left: 91.66666667%; - } - .col-sm-offset-10 { - margin-left: 83.33333333%; - } - .col-sm-offset-9 { - margin-left: 75%; - } - .col-sm-offset-8 { - margin-left: 66.66666667%; - } - .col-sm-offset-7 { - margin-left: 58.33333333%; - } - .col-sm-offset-6 { - margin-left: 50%; - } - .col-sm-offset-5 { - margin-left: 41.66666667%; - } - .col-sm-offset-4 { - margin-left: 33.33333333%; - } - .col-sm-offset-3 { - margin-left: 25%; - } - .col-sm-offset-2 { - margin-left: 16.66666667%; - } - .col-sm-offset-1 { - margin-left: 8.33333333%; - } - .col-sm-offset-0 { - margin-left: 0%; - } -} -@media (min-width: 992px) { - .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 { - float: left; - } - .col-md-12 { - width: 100%; - } - .col-md-11 { - width: 91.66666667%; - } - .col-md-10 { - width: 83.33333333%; - } - .col-md-9 { - width: 75%; - } - .col-md-8 { - width: 66.66666667%; - } - .col-md-7 { - width: 58.33333333%; - } - .col-md-6 { - width: 50%; - } - .col-md-5 { - width: 41.66666667%; - } - .col-md-4 { - width: 33.33333333%; - } - .col-md-3 { - width: 25%; - } - .col-md-2 { - width: 16.66666667%; - } - .col-md-1 { - width: 8.33333333%; - } - .col-md-pull-12 { - right: 100%; - } - .col-md-pull-11 { - right: 91.66666667%; - } - .col-md-pull-10 { - right: 83.33333333%; - } - .col-md-pull-9 { - right: 75%; - } - .col-md-pull-8 { - right: 66.66666667%; - } - .col-md-pull-7 { - right: 58.33333333%; - } - .col-md-pull-6 { - right: 50%; - } - .col-md-pull-5 { - right: 41.66666667%; - } - .col-md-pull-4 { - right: 33.33333333%; - } - .col-md-pull-3 { - right: 25%; - } - .col-md-pull-2 { - right: 16.66666667%; - } - .col-md-pull-1 { - right: 8.33333333%; - } - .col-md-pull-0 { - right: auto; - } - .col-md-push-12 { - left: 100%; - } - .col-md-push-11 { - left: 91.66666667%; - } - .col-md-push-10 { - left: 83.33333333%; - } - .col-md-push-9 { - left: 75%; - } - .col-md-push-8 { - left: 66.66666667%; - } - .col-md-push-7 { - left: 58.33333333%; - } - .col-md-push-6 { - left: 50%; - } - .col-md-push-5 { - left: 41.66666667%; - } - .col-md-push-4 { - left: 33.33333333%; - } - .col-md-push-3 { - left: 25%; - } - .col-md-push-2 { - left: 16.66666667%; - } - .col-md-push-1 { - left: 8.33333333%; - } - .col-md-push-0 { - left: auto; - } - .col-md-offset-12 { - margin-left: 100%; - } - .col-md-offset-11 { - margin-left: 91.66666667%; - } - .col-md-offset-10 { - margin-left: 83.33333333%; - } - .col-md-offset-9 { - margin-left: 75%; - } - .col-md-offset-8 { - margin-left: 66.66666667%; - } - .col-md-offset-7 { - margin-left: 58.33333333%; - } - .col-md-offset-6 { - margin-left: 50%; - } - .col-md-offset-5 { - margin-left: 41.66666667%; - } - .col-md-offset-4 { - margin-left: 33.33333333%; - } - .col-md-offset-3 { - margin-left: 25%; - } - .col-md-offset-2 { - margin-left: 16.66666667%; - } - .col-md-offset-1 { - margin-left: 8.33333333%; - } - .col-md-offset-0 { - margin-left: 0%; - } -} -@media (min-width: 1200px) { - .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 { - float: left; - } - .col-lg-12 { - width: 100%; - } - .col-lg-11 { - width: 91.66666667%; - } - .col-lg-10 { - width: 83.33333333%; - } - .col-lg-9 { - width: 75%; - } - .col-lg-8 { - width: 66.66666667%; - } - .col-lg-7 { - width: 58.33333333%; - } - .col-lg-6 { - width: 50%; - } - .col-lg-5 { - width: 41.66666667%; - } - .col-lg-4 { - width: 33.33333333%; - } - .col-lg-3 { - width: 25%; - } - .col-lg-2 { - width: 16.66666667%; - } - .col-lg-1 { - width: 8.33333333%; - } - .col-lg-pull-12 { - right: 100%; - } - .col-lg-pull-11 { - right: 91.66666667%; - } - .col-lg-pull-10 { - right: 83.33333333%; - } - .col-lg-pull-9 { - right: 75%; - } - .col-lg-pull-8 { - right: 66.66666667%; - } - .col-lg-pull-7 { - right: 58.33333333%; - } - .col-lg-pull-6 { - right: 50%; - } - .col-lg-pull-5 { - right: 41.66666667%; - } - .col-lg-pull-4 { - right: 33.33333333%; - } - .col-lg-pull-3 { - right: 25%; - } - .col-lg-pull-2 { - right: 16.66666667%; - } - .col-lg-pull-1 { - right: 8.33333333%; - } - .col-lg-pull-0 { - right: auto; - } - .col-lg-push-12 { - left: 100%; - } - .col-lg-push-11 { - left: 91.66666667%; - } - .col-lg-push-10 { - left: 83.33333333%; - } - .col-lg-push-9 { - left: 75%; - } - .col-lg-push-8 { - left: 66.66666667%; - } - .col-lg-push-7 { - left: 58.33333333%; - } - .col-lg-push-6 { - left: 50%; - } - .col-lg-push-5 { - left: 41.66666667%; - } - .col-lg-push-4 { - left: 33.33333333%; - } - .col-lg-push-3 { - left: 25%; - } - .col-lg-push-2 { - left: 16.66666667%; - } - .col-lg-push-1 { - left: 8.33333333%; - } - .col-lg-push-0 { - left: auto; - } - .col-lg-offset-12 { - margin-left: 100%; - } - .col-lg-offset-11 { - margin-left: 91.66666667%; - } - .col-lg-offset-10 { - margin-left: 83.33333333%; - } - .col-lg-offset-9 { - margin-left: 75%; - } - .col-lg-offset-8 { - margin-left: 66.66666667%; - } - .col-lg-offset-7 { - margin-left: 58.33333333%; - } - .col-lg-offset-6 { - margin-left: 50%; - } - .col-lg-offset-5 { - margin-left: 41.66666667%; - } - .col-lg-offset-4 { - margin-left: 33.33333333%; - } - .col-lg-offset-3 { - margin-left: 25%; - } - .col-lg-offset-2 { - margin-left: 16.66666667%; - } - .col-lg-offset-1 { - margin-left: 8.33333333%; - } - .col-lg-offset-0 { - margin-left: 0%; - } -} -table { - background-color: transparent; -} -caption { - padding-top: 8px; - padding-bottom: 8px; - color: #777777; - text-align: left; -} -th { - text-align: left; -} -.table { - width: 100%; - max-width: 100%; - margin-bottom: 20px; -} -.table > thead > tr > th, -.table > tbody > tr > th, -.table > tfoot > tr > th, -.table > thead > tr > td, -.table > tbody > tr > td, -.table > tfoot > tr > td { - padding: 8px; - line-height: 1.42857143; - vertical-align: top; - border-top: 1px solid #dddddd; -} -.table > thead > tr > th { - vertical-align: bottom; - border-bottom: 2px solid #dddddd; -} -.table > caption + thead > tr:first-child > th, -.table > colgroup + thead > tr:first-child > th, -.table > thead:first-child > tr:first-child > th, -.table > caption + thead > tr:first-child > td, -.table > colgroup + thead > tr:first-child > td, -.table > thead:first-child > tr:first-child > td { - border-top: 0; -} -.table > tbody + tbody { - border-top: 2px solid #dddddd; -} -.table .table { - background-color: #ffffff; -} -.table-condensed > thead > tr > th, -.table-condensed > tbody > tr > th, -.table-condensed > tfoot > tr > th, -.table-condensed > thead > tr > td, -.table-condensed > tbody > tr > td, -.table-condensed > tfoot > tr > td { - padding: 5px; -} -.table-bordered { - border: 1px solid #dddddd; -} -.table-bordered > thead > tr > th, -.table-bordered > tbody > tr > th, -.table-bordered > tfoot > tr > th, -.table-bordered > thead > tr > td, -.table-bordered > tbody > tr > td, -.table-bordered > tfoot > tr > td { - border: 1px solid #dddddd; -} -.table-bordered > thead > tr > th, -.table-bordered > thead > tr > td { - border-bottom-width: 2px; -} -.table-striped > tbody > tr:nth-of-type(odd) { - background-color: #f9f9f9; -} -.table-hover > tbody > tr:hover { - background-color: #f5f5f5; -} -table col[class*="col-"] { - position: static; - float: none; - display: table-column; -} -table td[class*="col-"], -table th[class*="col-"] { - position: static; - float: none; - display: table-cell; -} -.table > thead > tr > td.active, -.table > tbody > tr > td.active, -.table > tfoot > tr > td.active, -.table > thead > tr > th.active, -.table > tbody > tr > th.active, -.table > tfoot > tr > th.active, -.table > thead > tr.active > td, -.table > tbody > tr.active > td, -.table > tfoot > tr.active > td, -.table > thead > tr.active > th, -.table > tbody > tr.active > th, -.table > tfoot > tr.active > th { - background-color: #f5f5f5; -} -.table-hover > tbody > tr > td.active:hover, -.table-hover > tbody > tr > th.active:hover, -.table-hover > tbody > tr.active:hover > td, -.table-hover > tbody > tr:hover > .active, -.table-hover > tbody > tr.active:hover > th { - background-color: #e8e8e8; -} -.table > thead > tr > td.success, -.table > tbody > tr > td.success, -.table > tfoot > tr > td.success, -.table > thead > tr > th.success, -.table > tbody > tr > th.success, -.table > tfoot > tr > th.success, -.table > thead > tr.success > td, -.table > tbody > tr.success > td, -.table > tfoot > tr.success > td, -.table > thead > tr.success > th, -.table > tbody > tr.success > th, -.table > tfoot > tr.success > th { - background-color: #dff0d8; -} -.table-hover > tbody > tr > td.success:hover, -.table-hover > tbody > tr > th.success:hover, -.table-hover > tbody > tr.success:hover > td, -.table-hover > tbody > tr:hover > .success, -.table-hover > tbody > tr.success:hover > th { - background-color: #d0e9c6; -} -.table > thead > tr > td.info, -.table > tbody > tr > td.info, -.table > tfoot > tr > td.info, -.table > thead > tr > th.info, -.table > tbody > tr > th.info, -.table > tfoot > tr > th.info, -.table > thead > tr.info > td, -.table > tbody > tr.info > td, -.table > tfoot > tr.info > td, -.table > thead > tr.info > th, -.table > tbody > tr.info > th, -.table > tfoot > tr.info > th { - background-color: #d9edf7; -} -.table-hover > tbody > tr > td.info:hover, -.table-hover > tbody > tr > th.info:hover, -.table-hover > tbody > tr.info:hover > td, -.table-hover > tbody > tr:hover > .info, -.table-hover > tbody > tr.info:hover > th { - background-color: #c4e3f3; -} -.table > thead > tr > td.warning, -.table > tbody > tr > td.warning, -.table > tfoot > tr > td.warning, -.table > thead > tr > th.warning, -.table > tbody > tr > th.warning, -.table > tfoot > tr > th.warning, -.table > thead > tr.warning > td, -.table > tbody > tr.warning > td, -.table > tfoot > tr.warning > td, -.table > thead > tr.warning > th, -.table > tbody > tr.warning > th, -.table > tfoot > tr.warning > th { - background-color: #fcf8e3; -} -.table-hover > tbody > tr > td.warning:hover, -.table-hover > tbody > tr > th.warning:hover, -.table-hover > tbody > tr.warning:hover > td, -.table-hover > tbody > tr:hover > .warning, -.table-hover > tbody > tr.warning:hover > th { - background-color: #faf2cc; -} -.table > thead > tr > td.danger, -.table > tbody > tr > td.danger, -.table > tfoot > tr > td.danger, -.table > thead > tr > th.danger, -.table > tbody > tr > th.danger, -.table > tfoot > tr > th.danger, -.table > thead > tr.danger > td, -.table > tbody > tr.danger > td, -.table > tfoot > tr.danger > td, -.table > thead > tr.danger > th, -.table > tbody > tr.danger > th, -.table > tfoot > tr.danger > th { - background-color: #f2dede; -} -.table-hover > tbody > tr > td.danger:hover, -.table-hover > tbody > tr > th.danger:hover, -.table-hover > tbody > tr.danger:hover > td, -.table-hover > tbody > tr:hover > .danger, -.table-hover > tbody > tr.danger:hover > th { - background-color: #ebcccc; -} -.table-responsive { - overflow-x: auto; - min-height: 0.01%; -} -@media screen and (max-width: 767px) { - .table-responsive { - width: 100%; - margin-bottom: 15px; - overflow-y: hidden; - -ms-overflow-style: -ms-autohiding-scrollbar; - border: 1px solid #dddddd; - } - .table-responsive > .table { - margin-bottom: 0; - } - .table-responsive > .table > thead > tr > th, - .table-responsive > .table > tbody > tr > th, - .table-responsive > .table > tfoot > tr > th, - .table-responsive > .table > thead > tr > td, - .table-responsive > .table > tbody > tr > td, - .table-responsive > .table > tfoot > tr > td { - white-space: nowrap; - } - .table-responsive > .table-bordered { - border: 0; - } - .table-responsive > .table-bordered > thead > tr > th:first-child, - .table-responsive > .table-bordered > tbody > tr > th:first-child, - .table-responsive > .table-bordered > tfoot > tr > th:first-child, - .table-responsive > .table-bordered > thead > tr > td:first-child, - .table-responsive > .table-bordered > tbody > tr > td:first-child, - .table-responsive > .table-bordered > tfoot > tr > td:first-child { - border-left: 0; - } - .table-responsive > .table-bordered > thead > tr > th:last-child, - .table-responsive > .table-bordered > tbody > tr > th:last-child, - .table-responsive > .table-bordered > tfoot > tr > th:last-child, - .table-responsive > .table-bordered > thead > tr > td:last-child, - .table-responsive > .table-bordered > tbody > tr > td:last-child, - .table-responsive > .table-bordered > tfoot > tr > td:last-child { - border-right: 0; - } - .table-responsive > .table-bordered > tbody > tr:last-child > th, - .table-responsive > .table-bordered > tfoot > tr:last-child > th, - .table-responsive > .table-bordered > tbody > tr:last-child > td, - .table-responsive > .table-bordered > tfoot > tr:last-child > td { - border-bottom: 0; - } -} -.btn { - display: inline-block; - margin-bottom: 0; - font-weight: normal; - text-align: center; - vertical-align: middle; - -ms-touch-action: manipulation; - touch-action: manipulation; - cursor: pointer; - background-image: none; - border: 1px solid transparent; - white-space: nowrap; - padding: 6px 12px; - font-size: 14px; - line-height: 1.42857143; - border-radius: 4px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} -.btn:focus, -.btn:active:focus, -.btn.active:focus, -.btn.focus, -.btn:active.focus, -.btn.active.focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -.btn:hover, -.btn:focus, -.btn.focus { - color: #333333; - text-decoration: none; -} -.btn:active, -.btn.active { - outline: 0; - background-image: none; - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); -} -.btn.disabled, -.btn[disabled], -fieldset[disabled] .btn { - cursor: not-allowed; - pointer-events: none; - opacity: 0.65; - filter: alpha(opacity=65); - -webkit-box-shadow: none; - box-shadow: none; -} -.btn-default { - color: #333333; - background-color: #ffffff; - border-color: #cccccc; -} -.btn-default:hover, -.btn-default:focus, -.btn-default.focus, -.btn-default:active, -.btn-default.active, -.open > .dropdown-toggle.btn-default { - color: #333333; - background-color: #e6e6e6; - border-color: #adadad; -} -.btn-default:active, -.btn-default.active, -.open > .dropdown-toggle.btn-default { - background-image: none; -} -.btn-default.disabled, -.btn-default[disabled], -fieldset[disabled] .btn-default, -.btn-default.disabled:hover, -.btn-default[disabled]:hover, -fieldset[disabled] .btn-default:hover, -.btn-default.disabled:focus, -.btn-default[disabled]:focus, -fieldset[disabled] .btn-default:focus, -.btn-default.disabled.focus, -.btn-default[disabled].focus, -fieldset[disabled] .btn-default.focus, -.btn-default.disabled:active, -.btn-default[disabled]:active, -fieldset[disabled] .btn-default:active, -.btn-default.disabled.active, -.btn-default[disabled].active, -fieldset[disabled] .btn-default.active { - background-color: #ffffff; - border-color: #cccccc; -} -.btn-default .badge { - color: #ffffff; - background-color: #333333; -} -.btn-primary { - color: #ffffff; - background-color: #337ab7; - border-color: #2e6da4; -} -.btn-primary:hover, -.btn-primary:focus, -.btn-primary.focus, -.btn-primary:active, -.btn-primary.active, -.open > .dropdown-toggle.btn-primary { - color: #ffffff; - background-color: #286090; - border-color: #204d74; -} -.btn-primary:active, -.btn-primary.active, -.open > .dropdown-toggle.btn-primary { - background-image: none; -} -.btn-primary.disabled, -.btn-primary[disabled], -fieldset[disabled] .btn-primary, -.btn-primary.disabled:hover, -.btn-primary[disabled]:hover, -fieldset[disabled] .btn-primary:hover, -.btn-primary.disabled:focus, -.btn-primary[disabled]:focus, -fieldset[disabled] .btn-primary:focus, -.btn-primary.disabled.focus, -.btn-primary[disabled].focus, -fieldset[disabled] .btn-primary.focus, -.btn-primary.disabled:active, -.btn-primary[disabled]:active, -fieldset[disabled] .btn-primary:active, -.btn-primary.disabled.active, -.btn-primary[disabled].active, -fieldset[disabled] .btn-primary.active { - background-color: #337ab7; - border-color: #2e6da4; -} -.btn-primary .badge { - color: #337ab7; - background-color: #ffffff; -} -.btn-success { - color: #ffffff; - background-color: #5cb85c; - border-color: #4cae4c; -} -.btn-success:hover, -.btn-success:focus, -.btn-success.focus, -.btn-success:active, -.btn-success.active, -.open > .dropdown-toggle.btn-success { - color: #ffffff; - background-color: #449d44; - border-color: #398439; -} -.btn-success:active, -.btn-success.active, -.open > .dropdown-toggle.btn-success { - background-image: none; -} -.btn-success.disabled, -.btn-success[disabled], -fieldset[disabled] .btn-success, -.btn-success.disabled:hover, -.btn-success[disabled]:hover, -fieldset[disabled] .btn-success:hover, -.btn-success.disabled:focus, -.btn-success[disabled]:focus, -fieldset[disabled] .btn-success:focus, -.btn-success.disabled.focus, -.btn-success[disabled].focus, -fieldset[disabled] .btn-success.focus, -.btn-success.disabled:active, -.btn-success[disabled]:active, -fieldset[disabled] .btn-success:active, -.btn-success.disabled.active, -.btn-success[disabled].active, -fieldset[disabled] .btn-success.active { - background-color: #5cb85c; - border-color: #4cae4c; -} -.btn-success .badge { - color: #5cb85c; - background-color: #ffffff; -} -.btn-info { - color: #ffffff; - background-color: #5bc0de; - border-color: #46b8da; -} -.btn-info:hover, -.btn-info:focus, -.btn-info.focus, -.btn-info:active, -.btn-info.active, -.open > .dropdown-toggle.btn-info { - color: #ffffff; - background-color: #31b0d5; - border-color: #269abc; -} -.btn-info:active, -.btn-info.active, -.open > .dropdown-toggle.btn-info { - background-image: none; -} -.btn-info.disabled, -.btn-info[disabled], -fieldset[disabled] .btn-info, -.btn-info.disabled:hover, -.btn-info[disabled]:hover, -fieldset[disabled] .btn-info:hover, -.btn-info.disabled:focus, -.btn-info[disabled]:focus, -fieldset[disabled] .btn-info:focus, -.btn-info.disabled.focus, -.btn-info[disabled].focus, -fieldset[disabled] .btn-info.focus, -.btn-info.disabled:active, -.btn-info[disabled]:active, -fieldset[disabled] .btn-info:active, -.btn-info.disabled.active, -.btn-info[disabled].active, -fieldset[disabled] .btn-info.active { - background-color: #5bc0de; - border-color: #46b8da; -} -.btn-info .badge { - color: #5bc0de; - background-color: #ffffff; -} -.btn-warning { - color: #ffffff; - background-color: #f0ad4e; - border-color: #eea236; -} -.btn-warning:hover, -.btn-warning:focus, -.btn-warning.focus, -.btn-warning:active, -.btn-warning.active, -.open > .dropdown-toggle.btn-warning { - color: #ffffff; - background-color: #ec971f; - border-color: #d58512; -} -.btn-warning:active, -.btn-warning.active, -.open > .dropdown-toggle.btn-warning { - background-image: none; -} -.btn-warning.disabled, -.btn-warning[disabled], -fieldset[disabled] .btn-warning, -.btn-warning.disabled:hover, -.btn-warning[disabled]:hover, -fieldset[disabled] .btn-warning:hover, -.btn-warning.disabled:focus, -.btn-warning[disabled]:focus, -fieldset[disabled] .btn-warning:focus, -.btn-warning.disabled.focus, -.btn-warning[disabled].focus, -fieldset[disabled] .btn-warning.focus, -.btn-warning.disabled:active, -.btn-warning[disabled]:active, -fieldset[disabled] .btn-warning:active, -.btn-warning.disabled.active, -.btn-warning[disabled].active, -fieldset[disabled] .btn-warning.active { - background-color: #f0ad4e; - border-color: #eea236; -} -.btn-warning .badge { - color: #f0ad4e; - background-color: #ffffff; -} -.btn-danger { - color: #ffffff; - background-color: #d9534f; - border-color: #d43f3a; -} -.btn-danger:hover, -.btn-danger:focus, -.btn-danger.focus, -.btn-danger:active, -.btn-danger.active, -.open > .dropdown-toggle.btn-danger { - color: #ffffff; - background-color: #c9302c; - border-color: #ac2925; -} -.btn-danger:active, -.btn-danger.active, -.open > .dropdown-toggle.btn-danger { - background-image: none; -} -.btn-danger.disabled, -.btn-danger[disabled], -fieldset[disabled] .btn-danger, -.btn-danger.disabled:hover, -.btn-danger[disabled]:hover, -fieldset[disabled] .btn-danger:hover, -.btn-danger.disabled:focus, -.btn-danger[disabled]:focus, -fieldset[disabled] .btn-danger:focus, -.btn-danger.disabled.focus, -.btn-danger[disabled].focus, -fieldset[disabled] .btn-danger.focus, -.btn-danger.disabled:active, -.btn-danger[disabled]:active, -fieldset[disabled] .btn-danger:active, -.btn-danger.disabled.active, -.btn-danger[disabled].active, -fieldset[disabled] .btn-danger.active { - background-color: #d9534f; - border-color: #d43f3a; -} -.btn-danger .badge { - color: #d9534f; - background-color: #ffffff; -} -.btn-link { - color: #337ab7; - font-weight: normal; - border-radius: 0; -} -.btn-link, -.btn-link:active, -.btn-link.active, -.btn-link[disabled], -fieldset[disabled] .btn-link { - background-color: transparent; - -webkit-box-shadow: none; - box-shadow: none; -} -.btn-link, -.btn-link:hover, -.btn-link:focus, -.btn-link:active { - border-color: transparent; -} -.btn-link:hover, -.btn-link:focus { - color: #23527c; - text-decoration: underline; - background-color: transparent; -} -.btn-link[disabled]:hover, -fieldset[disabled] .btn-link:hover, -.btn-link[disabled]:focus, -fieldset[disabled] .btn-link:focus { - color: #777777; - text-decoration: none; -} -.btn-lg { - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; - border-radius: 6px; -} -.btn-sm { - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -.btn-xs { - padding: 1px 5px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -.btn-block { - display: block; - width: 100%; -} -.btn-block + .btn-block { - margin-top: 5px; -} -input[type="submit"].btn-block, -input[type="reset"].btn-block, -input[type="button"].btn-block { - width: 100%; -} -.clearfix:before, -.clearfix:after, -.dl-horizontal dd:before, -.dl-horizontal dd:after, -.container:before, -.container:after, -.container-fluid:before, -.container-fluid:after, -.row:before, -.row:after { - content: " "; - display: table; -} -.clearfix:after, -.dl-horizontal dd:after, -.container:after, -.container-fluid:after, -.row:after { - clear: both; -} -.center-block { - display: block; - margin-left: auto; - margin-right: auto; -} -.pull-right { - float: right !important; -} -.pull-left { - float: left !important; -} -.hide { - display: none !important; -} -.show { - display: block !important; -} -.invisible { - visibility: hidden; -} -.text-hide { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} -.hidden { - display: none !important; -} -.affix { - position: fixed; -} -@-ms-viewport { - width: device-width; -} -.visible-xs, -.visible-sm, -.visible-md, -.visible-lg { - display: none !important; -} -.visible-xs-block, -.visible-xs-inline, -.visible-xs-inline-block, -.visible-sm-block, -.visible-sm-inline, -.visible-sm-inline-block, -.visible-md-block, -.visible-md-inline, -.visible-md-inline-block, -.visible-lg-block, -.visible-lg-inline, -.visible-lg-inline-block { - display: none !important; -} -@media (max-width: 767px) { - .visible-xs { - display: block !important; - } - table.visible-xs { - display: table; - } - tr.visible-xs { - display: table-row !important; - } - th.visible-xs, - td.visible-xs { - display: table-cell !important; - } -} -@media (max-width: 767px) { - .visible-xs-block { - display: block !important; - } -} -@media (max-width: 767px) { - .visible-xs-inline { - display: inline !important; - } -} -@media (max-width: 767px) { - .visible-xs-inline-block { - display: inline-block !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm { - display: block !important; - } - table.visible-sm { - display: table; - } - tr.visible-sm { - display: table-row !important; - } - th.visible-sm, - td.visible-sm { - display: table-cell !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-block { - display: block !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-inline { - display: inline !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-inline-block { - display: inline-block !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md { - display: block !important; - } - table.visible-md { - display: table; - } - tr.visible-md { - display: table-row !important; - } - th.visible-md, - td.visible-md { - display: table-cell !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-block { - display: block !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-inline { - display: inline !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-inline-block { - display: inline-block !important; - } -} -@media (min-width: 1200px) { - .visible-lg { - display: block !important; - } - table.visible-lg { - display: table; - } - tr.visible-lg { - display: table-row !important; - } - th.visible-lg, - td.visible-lg { - display: table-cell !important; - } -} -@media (min-width: 1200px) { - .visible-lg-block { - display: block !important; - } -} -@media (min-width: 1200px) { - .visible-lg-inline { - display: inline !important; - } -} -@media (min-width: 1200px) { - .visible-lg-inline-block { - display: inline-block !important; - } -} -@media (max-width: 767px) { - .hidden-xs { - display: none !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .hidden-sm { - display: none !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .hidden-md { - display: none !important; - } -} -@media (min-width: 1200px) { - .hidden-lg { - display: none !important; - } -} -.visible-print { - display: none !important; -} -@media print { - .visible-print { - display: block !important; - } - table.visible-print { - display: table; - } - tr.visible-print { - display: table-row !important; - } - th.visible-print, - td.visible-print { - display: table-cell !important; - } -} -.visible-print-block { - display: none !important; -} -@media print { - .visible-print-block { - display: block !important; - } -} -.visible-print-inline { - display: none !important; -} -@media print { - .visible-print-inline { - display: inline !important; - } -} -.visible-print-inline-block { - display: none !important; -} -@media print { - .visible-print-inline-block { - display: inline-block !important; - } -} -@media print { - .hidden-print { - display: none !important; - } -} diff --git a/src/Orchard.Web/Modules/Orchard.Dashboards/Styles/bootstrap.min.css b/src/Orchard.Web/Modules/Orchard.Dashboards/Styles/bootstrap.min.css deleted file mode 100644 index abd760a63ff..00000000000 --- a/src/Orchard.Web/Modules/Orchard.Dashboards/Styles/bootstrap.min.css +++ /dev/null @@ -1,10 +0,0 @@ -/*! - * Bootstrap v3.3.4 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ - -/*! - * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=6737c6372ebd005d9906) - * Config saved to config.json and https://gist.github.com/6737c6372ebd005d9906 - *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role="button"]{cursor:pointer}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}mark,.mark{background-color:#fcf8e3;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:bold}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.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{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.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{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.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{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table-responsive{overflow-x:auto;min-height:0.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#333;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default.focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary:hover,.btn-primary:focus,.btn-primary.focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success.focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info.focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning.focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger.focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#337ab7;font-weight:normal;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after{content:" ";display:table}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none !important}@media (max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media (max-width:767px){.visible-xs-block{display:block !important}}@media (max-width:767px){.visible-xs-inline{display:inline !important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block !important}}@media (min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (min-width:1200px){.visible-lg-block{display:block !important}}@media (min-width:1200px){.visible-lg-inline{display:inline !important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block !important}}@media (max-width:767px){.hidden-xs{display:none !important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none !important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none !important}}@media (min-width:1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}.visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}.visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}@media print{.hidden-print{display:none !important}} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Dashboards/Views/Content.Dashboard.cshtml b/src/Orchard.Web/Modules/Orchard.Dashboards/Views/Content.Dashboard.cshtml index 0a231403606..acf2baa2f11 100644 --- a/src/Orchard.Web/Modules/Orchard.Dashboards/Views/Content.Dashboard.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Dashboards/Views/Content.Dashboard.cshtml @@ -1,6 +1,6 @@ @using Orchard.ContentManagement @{ - Style.Include("bootstrap.css", "bootstrap.min.css"); + Style.Require("Bootstrap"); Style.Require("FontAwesome"); Style.Include("dashboard.css"); } diff --git a/src/Orchard.Web/Modules/Orchard.Dashboards/Views/Dashboard/List.cshtml b/src/Orchard.Web/Modules/Orchard.Dashboards/Views/Dashboard/List.cshtml index 42023d7675c..0d10d0fea1a 100644 --- a/src/Orchard.Web/Modules/Orchard.Dashboards/Views/Dashboard/List.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Dashboards/Views/Dashboard/List.cshtml @@ -16,7 +16,7 @@ diff --git a/src/Orchard.Web/Modules/Orchard.Dashboards/Web.config b/src/Orchard.Web/Modules/Orchard.Dashboards/Web.config index d1587f722cd..c6b0cd12fc9 100644 --- a/src/Orchard.Web/Modules/Orchard.Dashboards/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Dashboards/Web.config @@ -7,7 +7,7 @@ - + @@ -21,14 +21,17 @@ + + + - + - + @@ -36,24 +39,41 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Dashboards/packages.config b/src/Orchard.Web/Modules/Orchard.Dashboards/packages.config index 6729ced4977..1c55d6960bb 100644 --- a/src/Orchard.Web/Modules/Orchard.Dashboards/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Dashboards/packages.config @@ -1,7 +1,8 @@  - - - - - \ No newline at end of file + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Module.txt b/src/Orchard.Web/Modules/Orchard.DesignerTools/Module.txt index 00821896236..2714abf4433 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Contains designer tools to ease the Themes development process FeatureName: Shape Tracing Category: Designer diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Orchard.DesignerTools.csproj b/src/Orchard.Web/Modules/Orchard.DesignerTools/Orchard.DesignerTools.csproj index 3adc23a8482..1ee8d67a463 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Orchard.DesignerTools.csproj +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Orchard.DesignerTools.csproj @@ -12,8 +12,8 @@ Properties Orchard.DesignerTools Orchard.DesignerTools - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,9 @@ + + + true @@ -49,38 +52,34 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -134,7 +133,7 @@ {2d1d92bb-4555-4cbe-8d0e-63563d6ce4c6} Orchard.Framework - false + $(MvcBuildViews) {194d3ccc-1153-474d-8176-fde8d7d0d0bd} @@ -142,10 +141,10 @@ - + - + 10.0 @@ -171,7 +170,7 @@ --> - + @@ -185,10 +184,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.DesignerTools/Properties/AssemblyInfo.cs index 26f564e4c27..4b707716284 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Scripts/orchard-designertools-shapetracing.js b/src/Orchard.Web/Modules/Orchard.DesignerTools/Scripts/orchard-designertools-shapetracing.js index 53c37da231a..e331f752975 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Scripts/orchard-designertools-shapetracing.js +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Scripts/orchard-designertools-shapetracing.js @@ -155,7 +155,7 @@ jQuery(function ($) { _this .nextUntil('[end-of="' + shapeNode.id + '"]') // all elements between the script beacons .find(':not(.shape-tracing-wrapper)') // all children but not inner beacons - .andSelf() // add the first level items + .addBack() // add the first level items .attr('shape-id', shapeNode.id) // add the shape-id attribute .each(function () { // assign a shapeNode instance to the DOM element @@ -298,7 +298,7 @@ jQuery(function ($) { var lastExpanded = null; // open the tree until the selected element - $('li[tree-shape-id="' + shapeNode.id + '"]').parents('li').andSelf().find('> .expando-glyph-container').each(function () { + $('li[tree-shape-id="' + shapeNode.id + '"]').parents('li').addBack().find('> .expando-glyph-container').each(function () { openExpando($(this)); }).each(function () { shapeTracingWindowTree.scrollTo(this, 0, { margin: true }); diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Views/ShapeTracingWrapper.cshtml b/src/Orchard.Web/Modules/Orchard.DesignerTools/Views/ShapeTracingWrapper.cshtml index 4d189d9f4af..7585c312a43 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Views/ShapeTracingWrapper.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Views/ShapeTracingWrapper.cshtml @@ -17,17 +17,17 @@ } // Code Mirror - Script.Include("CodeMirror/codemirror.js"); + Script.Include("CodeMirror/codemirror.js").AtHead(); Style.Include("CodeMirror/codemirror.css"); - Script.Include("CodeMirror/razor.js"); + Script.Include("CodeMirror/razor.js").AtHead(); Style.Include("CodeMirror/razor.css"); - Script.Include("CodeMirror/javascript.js"); - Style.Include("CodeMirror/javascript.css"); - Script.Include("CodeMirror/css.js"); + Script.Include("CodeMirror/javascript.js").AtHead(); + Style.Include("CodeMirror/javascript.css").AtHead(); + Script.Include("CodeMirror/css.js").AtHead(); Style.Include("CodeMirror/css.css"); - Script.Include("CodeMirror/htmlmixed.js"); + Script.Include("CodeMirror/htmlmixed.js").AtHead(); - Script.Include("jquery.tmpl.min.js"); + Script.Include("jquery.tmpl.min.js").AtHead(); } @Display(Model.Metadata.ChildContent) diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Web.config b/src/Orchard.Web/Modules/Orchard.DesignerTools/Web.config index bfeea149d0f..68ff8758d7e 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Web.config +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Web.config @@ -7,7 +7,7 @@ - + @@ -21,14 +21,17 @@ + + + - + - + @@ -36,25 +39,41 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/packages.config b/src/Orchard.Web/Modules/Orchard.DesignerTools/packages.config index 6729ced4977..1c55d6960bb 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/packages.config +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/packages.config @@ -1,7 +1,8 @@  - - - - - \ No newline at end of file + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Controllers/AdminController.cs index e576341f750..741cc8dc62f 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Controllers/AdminController.cs @@ -2,6 +2,7 @@ using System.Web.Mvc; using Orchard.DynamicForms.Services; using Orchard.DynamicForms.ViewModels; +using Orchard.Utility.Extensions; namespace Orchard.DynamicForms.Controllers { public class AdminController : Controller { @@ -17,5 +18,12 @@ public ActionResult Index() { }; return View(viewModel); } + + public ActionResult GetTechnicalName(string displayName, int version) { + return Json(new { + result = displayName.ToHtmlName(), + version = version + }); + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Controllers/FormController.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Controllers/FormController.cs index 67fde869c4a..0d482045728 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Controllers/FormController.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Controllers/FormController.cs @@ -48,7 +48,7 @@ public ActionResult Submit(int contentId, string formName) { if (form == null) { Logger.Warning("The specified form \"{0}\" could not be found.", formName); - _notifier.Warning(T("The specified form \"{0}\" could not be found.")); + _notifier.Warning(T("The specified form \"{0}\" could not be found.", formName)); return Redirect(urlReferrer); } diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Controllers/SubmissionAdminController.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Controllers/SubmissionAdminController.cs index 8fe29f0e787..051361e6533 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Controllers/SubmissionAdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Controllers/SubmissionAdminController.cs @@ -74,5 +74,11 @@ public ActionResult BulkDelete(IEnumerable submissionIds) { return Redirect(Request.UrlReferrer.ToString()); } + + public ActionResult Export(string id) => + File( + _formService.ExportSubmissions(id), + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "Export.xlsx"); } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/CheckboxElementDriver.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/CheckboxElementDriver.cs index 232cc725324..e9ffca8a951 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/CheckboxElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/CheckboxElementDriver.cs @@ -16,8 +16,8 @@ public CheckboxElementDriver(IFormsBasedElementServices formsServices, ITokenize } protected override EditorResult OnBuildEditor(CheckBox element, ElementEditorContext context) { - var autoLabelEditor = BuildForm(context, "AutoLabel"); - var checkBoxEditor = BuildForm(context, "CheckBox"); + var autoLabelEditor = BuildForm(context, "AutoLabel", "Properties:1"); + var checkBoxEditor = BuildForm(context, "CheckBox", "Properties:15"); var checkBoxValidation = BuildForm(context, "CheckBoxValidation", "Validation:10"); return Editor(context, autoLabelEditor, checkBoxEditor, checkBoxValidation); diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/CommonFormElementDriver.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/CommonFormElementDriver.cs index dbdc9dc55fd..63f62aa961a 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/CommonFormElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/CommonFormElementDriver.cs @@ -47,5 +47,8 @@ protected override void OnDisplaying(FormElement element, ElementDisplayingConte context.ElementShape.Child.Add(New.PlaceChildContent(Source: context.ElementShape)); } + protected override EditorResult OnBuildEditor(FormElement element, ElementEditorContext context) { + return Editor(context, BuildForm(context, "CommonFormElement", "Properties:10")); + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/EmailFieldElementDriver.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/EmailFieldElementDriver.cs index 91c9da709b0..af8bb691a55 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/EmailFieldElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/EmailFieldElementDriver.cs @@ -15,11 +15,12 @@ public EmailFieldElementDriver(IFormsBasedElementServices formsServices, ITokeni } protected override EditorResult OnBuildEditor(EmailField element, ElementEditorContext context) { - var autoLabelEditor = BuildForm(context, "AutoLabel"); - var emailFieldEditor = BuildForm(context, "EmailField"); + var autoLabelEditor = BuildForm(context, "AutoLabel", "Properties:1"); + var placeholderEditor = BuildForm(context, "Placeholder", "Properties:10"); + var emailFieldEditor = BuildForm(context, "EmailField", "Properties:15"); var emailFieldValidation = BuildForm(context, "EmailFieldValidation", "Validation:10"); - return Editor(context, autoLabelEditor, emailFieldEditor, emailFieldValidation); + return Editor(context, autoLabelEditor, placeholderEditor, emailFieldEditor, emailFieldValidation); } protected override void DescribeForm(DescribeContext context) { @@ -80,6 +81,7 @@ protected override void OnDisplaying(EmailField element, ElementDisplayingContex var tokenData = context.GetTokenData(); context.ElementShape.ProcessedName = _tokenizer.Replace(element.Name, tokenData); context.ElementShape.ProcessedLabel = _tokenizer.Replace(element.Label, tokenData, new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); + context.ElementShape.ProcessedPlaceholder = _tokenizer.Replace(element.Placeholder, tokenData, new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); // Allow the initial value to be tokenized. // If a value was posted, use that value instead (without tokenizing it). diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/EnumerationElementDriver.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/EnumerationElementDriver.cs index 3e67340ea56..96414b40d93 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/EnumerationElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/EnumerationElementDriver.cs @@ -19,8 +19,8 @@ public EnumerationElementDriver(IFormsBasedElementServices formsServices, IToken } protected override EditorResult OnBuildEditor(Enumeration element, ElementEditorContext context) { - var autoLabelEditor = BuildForm(context, "AutoLabel"); - var enumerationEditor = BuildForm(context, "Enumeration"); + var autoLabelEditor = BuildForm(context, "AutoLabel", "Properties:1"); + var enumerationEditor = BuildForm(context, "Enumeration", "Properties:15"); var checkBoxValidation = BuildForm(context, "EnumerationValidation", "Validation:10"); return Editor(context, autoLabelEditor, enumerationEditor, checkBoxValidation); diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/PasswordFieldElementDriver.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/PasswordFieldElementDriver.cs index a030954fe62..3d7e5c1c0e8 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/PasswordFieldElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/PasswordFieldElementDriver.cs @@ -15,10 +15,11 @@ public PasswordFieldElementDriver(IFormsBasedElementServices formsServices, ITok } protected override EditorResult OnBuildEditor(PasswordField element, ElementEditorContext context) { - var autoLabelEditor = BuildForm(context, "AutoLabel"); + var autoLabelEditor = BuildForm(context, "AutoLabel", "Properties:1"); + var placeholderEditor = BuildForm(context, "Placeholder", "Properties:10"); var passwordFieldValidation = BuildForm(context, "PasswordFieldValidation", "Validation:10"); - return Editor(context, autoLabelEditor, passwordFieldValidation); + return Editor(context, autoLabelEditor, placeholderEditor, passwordFieldValidation); } protected override void DescribeForm(DescribeContext context) { @@ -74,8 +75,10 @@ protected override void DescribeForm(DescribeContext context) { } protected override void OnDisplaying(PasswordField element, ElementDisplayingContext context) { - context.ElementShape.ProcessedName = _tokenizer.Replace(element.Name, context.GetTokenData()); - context.ElementShape.ProcessedLabel = _tokenizer.Replace(element.Label, context.GetTokenData(), new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); + var tokenData = context.GetTokenData(); + context.ElementShape.ProcessedName = _tokenizer.Replace(element.Name, tokenData); + context.ElementShape.ProcessedLabel = _tokenizer.Replace(element.Label, tokenData, new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); + context.ElementShape.ProcessedPlaceholder = _tokenizer.Replace(element.Placeholder, tokenData, new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/QueryElementDriver.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/QueryElementDriver.cs index 83399063e26..33108e6ade1 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/QueryElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/QueryElementDriver.cs @@ -31,8 +31,8 @@ public QueryElementDriver(IFormsBasedElementServices formsServices, IProjectionM } protected override EditorResult OnBuildEditor(Query element, ElementEditorContext context) { - var autoLabelEditor = BuildForm(context, "AutoLabel"); - var enumerationEditor = BuildForm(context, "QueryForm"); + var autoLabelEditor = BuildForm(context, "AutoLabel", "Properties:1"); + var enumerationEditor = BuildForm(context, "QueryForm", "Properties:15"); var checkBoxValidation = BuildForm(context, "QueryValidation", "Validation:10"); return Editor(context, autoLabelEditor, enumerationEditor, checkBoxValidation); @@ -174,5 +174,29 @@ private IEnumerable GetRuntimeValues(Query element) { var runtimeValue = element.RuntimeValue; return runtimeValue != null ? runtimeValue.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) : Enumerable.Empty(); } + + protected override void OnExporting(Query element, ExportElementContext context) { + base.OnExporting(element, context); + if (element.QueryId == null) + return; + var queryContentItem = _contentManager.Get(element.QueryId.Value); + if (queryContentItem == null) + return; + context.Element.Data.Add("QueryElementIdentity", _contentManager.GetItemMetadata(queryContentItem).Identity.ToString()); + } + + protected override void OnImportCompleted(Query element, ImportElementContext context) { + base.OnImported(element, context); + if (!context.Element.Data.Keys.Contains("QueryElementIdentity")) + return; + var queryIdentifier = context.Element.Data["QueryElementIdentity"]; + var queryContentItem = context.Session.GetItemFromSession(queryIdentifier).Content; + if (queryContentItem == null) + return; + element.QueryId = queryContentItem.ContentItem.Id; + if (!context.Element.Data.Keys.Contains("QueryId")) + return; + context.Element.Data["QueryId"] = element.QueryId.ToString(); + } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/TaxonomyElementDriver.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/TaxonomyElementDriver.cs index 2b3614b1b63..47b64dadfdc 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/TaxonomyElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/TaxonomyElementDriver.cs @@ -3,12 +3,14 @@ using System.Globalization; using System.Linq; using System.Web.Mvc; +using Orchard.ContentManagement; using Orchard.DynamicForms.Elements; using Orchard.Environment.Extensions; using Orchard.Layouts.Framework.Display; using Orchard.Layouts.Framework.Drivers; using Orchard.Layouts.Helpers; using Orchard.Layouts.Services; +using Orchard.Taxonomies.Models; using Orchard.Taxonomies.Services; using Orchard.Tokens; using DescribeContext = Orchard.Forms.Services.DescribeContext; @@ -18,16 +20,22 @@ namespace Orchard.DynamicForms.Drivers { public class TaxonomyElementDriver : FormsElementDriver { private readonly ITaxonomyService _taxonomyService; private readonly ITokenizer _tokenizer; + private readonly IContentManager _contentManager; - public TaxonomyElementDriver(IFormsBasedElementServices formsServices, ITaxonomyService taxonomyService, ITokenizer tokenizer) + public TaxonomyElementDriver( + IFormsBasedElementServices formsServices, + ITaxonomyService taxonomyService, + ITokenizer tokenizer, + IContentManager contentManager) : base(formsServices) { _taxonomyService = taxonomyService; _tokenizer = tokenizer; + _contentManager = contentManager; } protected override EditorResult OnBuildEditor(Taxonomy element, ElementEditorContext context) { - var autoLabelEditor = BuildForm(context, "AutoLabel"); - var enumerationEditor = BuildForm(context, "TaxonomyForm"); + var autoLabelEditor = BuildForm(context, "AutoLabel", "Properties:1"); + var enumerationEditor = BuildForm(context, "TaxonomyForm", "Properties:15"); var checkBoxValidation = BuildForm(context, "TaxonomyValidation", "Validation:10"); return Editor(context, autoLabelEditor, enumerationEditor, checkBoxValidation); @@ -146,6 +154,24 @@ protected override void OnDisplaying(Taxonomy element, ElementDisplayingContext context.ElementShape.Metadata.Alternates.Add(String.Format("Elements_{0}_{1}__{2}", typeName, displayType, element.InputType)); } + protected override void OnExporting(Taxonomy element, ExportElementContext context) { + var taxonomy = _contentManager.Get(element.TaxonomyId ?? 0); + + if (taxonomy == null) return; + + var taxonomyIdentity = _contentManager.GetItemMetadata(taxonomy)?.Identity?.ToString(); + + if (string.IsNullOrEmpty(taxonomyIdentity)) context.ExportableData["TaxonomyId"] = taxonomyIdentity; + } + + protected override void OnImportCompleted(Taxonomy element, ImportElementContext context) { + var taxonomyIdentity = context.ExportableData.Get("TaxonomyId"); + + var taxonomy = string.IsNullOrEmpty(taxonomyIdentity) ? context.Session.GetItemFromSession(taxonomyIdentity) : null; + + if (taxonomy != null) element.TaxonomyId = taxonomy.Id; + } + private IEnumerable GetTermOptions(Taxonomy element, string displayType, int? taxonomyId, IDictionary tokenData) { var optionLabel = element.OptionLabel; var runtimeValues = GetRuntimeValues(element); diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/TextAreaElementDriver.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/TextAreaElementDriver.cs index 3dc880b8aff..8bf469878f4 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/TextAreaElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/TextAreaElementDriver.cs @@ -14,11 +14,12 @@ public TextAreaElementDriver(IFormsBasedElementServices formsServices, ITokenize } protected override EditorResult OnBuildEditor(TextArea element, ElementEditorContext context) { - var autoLabelEditor = BuildForm(context, "AutoLabel"); - var textAreaEditor = BuildForm(context, "TextArea"); + var autoLabelEditor = BuildForm(context, "AutoLabel", "Properties:1"); + var placeholderEditor = BuildForm(context, "Placeholder", "Properties:10"); + var textAreaEditor = BuildForm(context, "TextArea", "Properties:15"); var textAreaValidation = BuildForm(context, "TextAreaValidation", "Validation:10"); - return Editor(context, autoLabelEditor, textAreaEditor, textAreaValidation); + return Editor(context, autoLabelEditor, placeholderEditor, textAreaEditor, textAreaValidation); } protected override void DescribeForm(DescribeContext context) { @@ -91,6 +92,7 @@ protected override void OnDisplaying(TextArea element, ElementDisplayingContext var tokenData = context.GetTokenData(); context.ElementShape.ProcessedName = _tokenizer.Replace(element.Name, tokenData); context.ElementShape.ProcessedLabel = _tokenizer.Replace(element.Label, tokenData, new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); + context.ElementShape.ProcessedPlaceholder = _tokenizer.Replace(element.Placeholder, tokenData, new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); // Allow the initial value to be tokenized. // If a value was posted, use that value instead (without tokenizing it). diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/TextFieldElementDriver.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/TextFieldElementDriver.cs index c34a454df73..e3bf452ebff 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/TextFieldElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/TextFieldElementDriver.cs @@ -15,11 +15,12 @@ public TextFieldElementDriver(IFormsBasedElementServices formsServices, ITokeniz } protected override EditorResult OnBuildEditor(TextField element, ElementEditorContext context) { - var autoLabelEditor = BuildForm(context, "AutoLabel"); - var textFieldEditor = BuildForm(context, "TextField"); + var autoLabelEditor = BuildForm(context, "AutoLabel", "Properties:1"); + var placeholderEditor = BuildForm(context, "Placeholder", "Properties:10"); + var textFieldEditor = BuildForm(context, "TextField", "Properties:15"); var textFieldValidation = BuildForm(context, "TextFieldValidation", "Validation:10"); - return Editor(context, autoLabelEditor, textFieldEditor, textFieldValidation); + return Editor(context, autoLabelEditor, placeholderEditor, textFieldEditor, textFieldValidation); } protected override void DescribeForm(DescribeContext context) { @@ -86,6 +87,7 @@ protected override void OnDisplaying(TextField element, ElementDisplayingContext var tokenData = context.GetTokenData(); context.ElementShape.ProcessedName = _tokenizer.Replace(element.Name, tokenData); context.ElementShape.ProcessedLabel = _tokenizer.Replace(element.Label, tokenData, new ReplaceOptions {Encoding = ReplaceOptions.NoEncode}); + context.ElementShape.ProcessedPlaceholder = _tokenizer.Replace(element.Placeholder, tokenData, new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); // Allow the initial value to be tokenized. // If a value was posted, use that value instead (without tokenizing it). diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/UrlFieldElementDriver.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/UrlFieldElementDriver.cs index 05ecc9c040b..9d74f16e9ea 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/UrlFieldElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/UrlFieldElementDriver.cs @@ -15,11 +15,12 @@ public UrlFieldElementDriver(IFormsBasedElementServices formsServices, ITokenize } protected override EditorResult OnBuildEditor(UrlField element, ElementEditorContext context) { - var autoLabelEditor = BuildForm(context, "AutoLabel"); - var webAddressFieldEditor = BuildForm(context, "UrlField"); + var autoLabelEditor = BuildForm(context, "AutoLabel", "Properties:1"); + var placeholderEditor = BuildForm(context, "Placeholder", "Properties:10"); + var webAddressFieldEditor = BuildForm(context, "UrlField", "Properties:15"); var webAddressFieldValidation = BuildForm(context, "UrlFieldValidation", "Validation:10"); - return Editor(context, autoLabelEditor, webAddressFieldEditor, webAddressFieldValidation); + return Editor(context, autoLabelEditor, placeholderEditor, webAddressFieldEditor, webAddressFieldValidation); } protected override void DescribeForm(DescribeContext context) { @@ -74,6 +75,7 @@ protected override void OnDisplaying(UrlField element, ElementDisplayingContext var tokenData = context.GetTokenData(); context.ElementShape.ProcessedName = _tokenizer.Replace(element.Name, tokenData); context.ElementShape.ProcessedLabel = _tokenizer.Replace(element.Label, tokenData, new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); + context.ElementShape.ProcessedPlaceholder = _tokenizer.Replace(element.Placeholder, tokenData, new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); // Allow the initial value to be tokenized. // If a value was posted, use that value instead (without tokenizing it). diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/ValidationElementDriver.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/ValidationElementDriver.cs deleted file mode 100644 index eb203b84e32..00000000000 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Drivers/ValidationElementDriver.cs +++ /dev/null @@ -1,94 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using Orchard.DynamicForms.Elements; -//using Orchard.DynamicForms.Helpers; -//using Orchard.DynamicForms.Services; -//using Orchard.DynamicForms.Services.Models; -//using Orchard.DynamicForms.ViewModels; -//using Orchard.Forms.Services; -//using Orchard.Layouts.Framework.Display; -//using Orchard.Layouts.Framework.Drivers; -//using Orchard.Layouts.Helpers; - -//namespace Orchard.DynamicForms.Drivers { -// public class ValidationElementDriver : ElementDriver { -// private readonly IValidationManager _validationManager; -// private readonly IFormManager _formManager; - -// public ValidationElementDriver(IValidationManager validationManager, IFormManager formManager) { -// _validationManager = validationManager; -// _formManager = formManager; -// } - -// protected override EditorResult OnBuildEditor(FormElement element, ElementEditorContext context) { -// var validatorNames = element.ValidatorNames.ToArray(); - -// var validators = new FieldValidationSettingsViewModel { -// Validators = _validationManager.GetValidatorsByNames(validatorNames).Select(x => new FieldValidationSettingViewModel() { -// Name = x.Name, -// SettingsEditor = BuildSettingsEditor(context, x) -// }).ToList() -// }; - -// if (context.Updater != null) { -// var viewModel = new FieldValidationSettingsViewModel(); -// if (context.Updater.TryUpdateModel(viewModel, null, null, null)) { -// if (viewModel.Validators != null) { -// foreach (var validatorModel in viewModel.Validators) { -// var validator = validators.Validators.SingleOrDefault(x => x.Name == validatorModel.Name); - -// if (validator == null) -// continue; - -// validator.Enabled = validatorModel.Enabled; -// validator.CustomValidationMessage = validatorModel.CustomValidationMessage; -// } -// } -// validators.ShowValidationMessage = viewModel.ShowValidationMessage; -// } -// } - -// // Fetch validation descriptors. -// foreach (var validator in validators.Validators) { -// validator.Descriptor = _validationManager.GetValidatorByName(validator.Name); -// } - -// var validatorsEditor = context.ShapeFactory.EditorTemplate(TemplateName: "Validators", Model: validators); -// validatorsEditor.Metadata.Position = "Validation:10"; - -// return Editor(context, validatorsEditor); -// } - -// protected override void OnDisplaying(FormElement element, ElementDisplayingContext context) { -// if (context.DisplayType == "Design" || element.Form == null) -// return; - -// if (element.Form.EnableClientValidation != true) { -// context.ElementShape.ClientValidationAttributes = new Dictionary(); -// return; -// } - -// var clientAttributes = new Dictionary { -// {"data-val", "true"} -// }; - -// foreach (var validatorSetting in element.ValidationSettings.Validators.Enabled()) { -// var validatorDescriptor = _validationManager.GetValidatorByName(validatorSetting.Name); -// var clientValidationRegistrationContext = new ClientValidationRegistrationContext(element, validatorSetting, validatorDescriptor); - -// validatorDescriptor.ClientAttributes(clientValidationRegistrationContext); -// clientAttributes.Combine(clientValidationRegistrationContext.ClientAttributes); -// } - -// context.ElementShape.ClientValidationAttributes = clientAttributes; -// } - -// private dynamic BuildSettingsEditor(ElementEditorContext context, ValidatorDescriptor validatorDescriptor) { -// if (String.IsNullOrWhiteSpace(validatorDescriptor.SettingsFormName)) -// return null; - -// return _formManager.Bind(_formManager.Build(validatorDescriptor.SettingsFormName), context.ValueProvider); -// } -// } -//} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/EmailField.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/EmailField.cs index 4cf872a22f7..345e2c55397 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/EmailField.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/EmailField.cs @@ -1,7 +1,7 @@ using Orchard.DynamicForms.Validators.Settings; namespace Orchard.DynamicForms.Elements { - public class EmailField : LabeledFormElement { + public class EmailField : FormElementWithPlaceholder { public EmailFieldValidationSettings ValidationSettings { get { return Data.GetModel(""); } } diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/FormElementWithPlaceholder.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/FormElementWithPlaceholder.cs new file mode 100644 index 00000000000..2e04d836392 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/FormElementWithPlaceholder.cs @@ -0,0 +1,10 @@ +using Orchard.Layouts.Helpers; + +namespace Orchard.DynamicForms.Elements { + public abstract class FormElementWithPlaceholder : LabeledFormElement { + public string Placeholder { + get { return this.Retrieve(x => x.Placeholder); } + set { this.Store(x => x.Placeholder, value); } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/PasswordField.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/PasswordField.cs index 8625646f3a9..13f3644128d 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/PasswordField.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/PasswordField.cs @@ -1,7 +1,7 @@ using Orchard.DynamicForms.Validators.Settings; namespace Orchard.DynamicForms.Elements { - public class PasswordField : LabeledFormElement { + public class PasswordField : FormElementWithPlaceholder { public PasswordFieldValidationSettings ValidationSettings { get { return Data.GetModel(""); } } diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/TextArea.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/TextArea.cs index f4e232dc69b..f5b6e5ee1b2 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/TextArea.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/TextArea.cs @@ -2,7 +2,7 @@ using Orchard.Layouts.Helpers; namespace Orchard.DynamicForms.Elements { - public class TextArea : LabeledFormElement { + public class TextArea : FormElementWithPlaceholder { public int? Rows { get { return this.Retrieve(x => x.Rows); } set { this.Store(x => x.Rows, value); } diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/TextField.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/TextField.cs index ca8b170efa2..ec947683255 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/TextField.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/TextField.cs @@ -1,7 +1,7 @@ using Orchard.DynamicForms.Validators.Settings; namespace Orchard.DynamicForms.Elements { - public class TextField : LabeledFormElement { + public class TextField : FormElementWithPlaceholder { public TextFieldValidationSettings ValidationSettings { get { return Data.GetModel(""); } } diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/UrlField.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/UrlField.cs index 83e24971dbf..c0fba81964b 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/UrlField.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Elements/UrlField.cs @@ -1,7 +1,7 @@ using Orchard.DynamicForms.Validators.Settings; namespace Orchard.DynamicForms.Elements { - public class UrlField : LabeledFormElement { + public class UrlField : FormElementWithPlaceholder { public UrlFieldValidationSettings ValidationSettings { get { return Data.GetModel(""); } } diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/AutoLabelForm.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/AutoLabelForm.cs index ae36dca16b1..40c8fb92491 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/AutoLabelForm.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/AutoLabelForm.cs @@ -20,8 +20,8 @@ public void Describe(DescribeContext context) { Name: "Label", Title: "Label", Classes: new[] { "text", "large", "tokenized" }, - Description: T("The label text to render."), - EnabledBy: "ShowLabel")); + Description: T("The label text to render.")), + _AutoLabelScript: shape.AutoLabelScript()); return form; }); diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/PlaceholderForm.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/PlaceholderForm.cs new file mode 100644 index 00000000000..95386e0a086 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/PlaceholderForm.cs @@ -0,0 +1,22 @@ +using Orchard.Forms.Services; +using DescribeContext = Orchard.Forms.Services.DescribeContext; + +namespace Orchard.DynamicForms.Forms { + public class PlaceholderForm : Component, IFormProvider { + public void Describe(DescribeContext context) { + context.Form("Placeholder", factory => { + var shape = (dynamic)factory; + var form = shape.Fieldset( + Id: "Placeholder", + _Placeholder: shape.Textbox( + Id: "Placeholder", + Name: "Placeholder", + Title: "Placeholder", + Classes: new[] { "text", "large", "tokenized" }, + Description: T("The text to render as placeholder."))); + + return form; + }); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Handlers/FormSubmissionCoordinator.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Handlers/FormSubmissionCoordinator.cs index 87bf0ba6aa2..361037b400c 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Handlers/FormSubmissionCoordinator.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Handlers/FormSubmissionCoordinator.cs @@ -50,6 +50,7 @@ public override void Validated(FormValidatedEventContext context) { var contentItem = default(ContentItem); if (form.CreateContent == true && !String.IsNullOrWhiteSpace(form.FormBindingContentType)) { contentItem = formService.CreateContentItem(form, context.ValueProvider); + formTokenContext.CreatedContent = contentItem; } // Notifiy. @@ -60,4 +61,4 @@ public override void Validated(FormValidatedEventContext context) { _workflowManager.TriggerEvent(DynamicFormSubmittedActivity.EventName, contentItem, () => tokenData); } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Helpers/NameValueCollectionExtensions.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Helpers/NameValueCollectionExtensions.cs deleted file mode 100644 index cdd14b43d54..00000000000 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Helpers/NameValueCollectionExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Specialized; -using System.Linq; -using System.Web; - -namespace Orchard.DynamicForms.Helpers { - public static class NameValueCollectionExtensions { - public static string ToQueryString(this NameValueCollection nameValues) { - return String.Join("&", (from string name in nameValues select String.Concat(name, "=", HttpUtility.UrlEncode(nameValues[name]))).ToArray()); - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Module.txt b/src/Orchard.Web/Modules/Orchard.DynamicForms/Module.txt index 766b597bc11..126c9d461b2 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Module.txt @@ -2,8 +2,8 @@ Name: Dynamic Forms AntiForgery: enabled Author: The Orchard Team Website: http://www.orchardproject.net/ -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Create custom forms like contact forms using layouts. Features: Orchard.DynamicForms: diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Orchard.DynamicForms.csproj b/src/Orchard.Web/Modules/Orchard.DynamicForms/Orchard.DynamicForms.csproj index e3133ef217a..c2cc01b7bcb 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Orchard.DynamicForms.csproj +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Orchard.DynamicForms.csproj @@ -12,8 +12,8 @@ Properties Orchard.DynamicForms Orchard.DynamicForms - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -25,6 +25,10 @@ + Latest + + + true @@ -48,14 +52,21 @@ false + + ..\..\..\packages\DocumentFormat.OpenXml.3.0.2\lib\net46\DocumentFormat.OpenXml.dll + + + ..\..\..\packages\DocumentFormat.OpenXml.Framework.3.0.2\lib\net46\DocumentFormat.OpenXml.Framework.dll + + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - - ..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True + + ..\..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll @@ -63,6 +74,7 @@ 3.5 + @@ -70,33 +82,28 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll + @@ -118,12 +125,12 @@ - - - + + + @@ -131,12 +138,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {91bc2e7f-da04-421c-98ef-76d37cec130c} @@ -266,7 +273,6 @@ - @@ -304,6 +310,7 @@ + @@ -332,7 +339,6 @@ - @@ -547,14 +553,19 @@ - + + + + + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - + @@ -588,7 +599,7 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Properties/AssemblyInfo.cs index 2bbf705d9f3..1a4c86349e7 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Properties/AssemblyInfo.cs @@ -32,6 +32,6 @@ // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Recipes/Builders/FormSubmissionsStep.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Recipes/Builders/FormSubmissionsStep.cs index 8a820dc0592..206c15cf9bd 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Recipes/Builders/FormSubmissionsStep.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Recipes/Builders/FormSubmissionsStep.cs @@ -3,12 +3,17 @@ using Orchard.DynamicForms.Services; using Orchard.Localization; using Orchard.Recipes.Services; +using System.Collections.Generic; +using Orchard.ContentManagement; +using Orchard.DynamicForms.ViewModels; namespace Orchard.DynamicForms.Recipes.Builders { public class FormSubmissionsStep : RecipeBuilderStep { private readonly IFormService _formService; + public FormSubmissionsStep(IFormService formService) { _formService = formService; + SelectedForms = new List(); } public override string Name { @@ -23,29 +28,43 @@ public override LocalizedString Description { get { return T("Exports submitted forms."); } } + public IList SelectedForms { get; set; } + public override dynamic BuildEditor(dynamic shapeFactory) { - // TODO: Implement an editor that enables the user to select which forms to export. - return null; + return UpdateEditor(shapeFactory, null); } - public override void Build(BuildContext context) { - var submissions = _formService.GetSubmissions().ToArray(); + public override dynamic UpdateEditor(dynamic shapeFactory, IUpdateModel updater) { + List forms = new List(); - if (!submissions.Any()) { - return; + if (updater != null && updater.TryUpdateModel(forms, Prefix, null, null)) { + SelectedForms = forms.Where(x => x.Export).Select(x => x.FormName).ToList(); + } + else { + forms = _formService.GetSubmissions().OrderBy(x => x.FormName).GroupBy(y => y.FormName) + .Select(x => new FormExportEntry { FormName = x.FirstOrDefault().FormName }) + .ToList(); } - var forms = submissions.GroupBy(x => x.FormName); - var root = new XElement("Forms"); - context.RecipeDocument.Element("Orchard").Add(root); - - foreach (var form in forms) { - root.Add(new XElement("Form", - new XAttribute("Name", form.Key), - new XElement("Submissions", form.Select(submission => - new XElement("Submission", - new XAttribute("CreatedUtc", submission.CreatedUtc), - new XCData(submission.FormData)))))); + return shapeFactory.EditorTemplate(TemplateName: "BuilderSteps/FormSubmissions", Model: forms, Prefix: Prefix); + } + + public override void Build(BuildContext context) { + if (SelectedForms.Count() > 0) { + var root = new XElement("Forms"); + context.RecipeDocument.Element("Orchard").Add(root); + + foreach (var form in SelectedForms) { + var submissions = _formService.GetSubmissions(form); + if (submissions.Count() > 0) { + root.Add(new XElement("Form", + new XAttribute("Name", form), + new XElement("Submissions", submissions.Select(submission => + new XElement("Submission", + new XAttribute("CreatedUtc", submission.CreatedUtc), + new XCData(submission.FormData)))))); + } + } } } } diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/FormService.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/FormService.cs index ab24a07bf50..603f5099d7e 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/FormService.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/FormService.cs @@ -2,9 +2,13 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Data; +using System.IO; using System.Linq; using System.Web; using System.Web.Mvc; +using DocumentFormat.OpenXml; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Spreadsheet; using Orchard.Collections; using Orchard.ContentManagement; using Orchard.ContentManagement.MetaData; @@ -21,6 +25,7 @@ using Orchard.Layouts.Services; using Orchard.Localization.Services; using Orchard.Services; +using Orchard.Utility.Extensions; namespace Orchard.DynamicForms.Services { public class FormService : IFormService { @@ -38,16 +43,16 @@ public class FormService : IFormService { private readonly ICultureAccessor _cultureAccessor; public FormService( - ILayoutSerializer serializer, - IClock clock, - IRepository submissionRepository, - IFormElementEventHandler elementHandlers, - IContentDefinitionManager contentDefinitionManager, - IBindingManager bindingManager, - IDynamicFormEventHandler formEventHandler, + ILayoutSerializer serializer, + IClock clock, + IRepository submissionRepository, + IFormElementEventHandler elementHandlers, + IContentDefinitionManager contentDefinitionManager, + IBindingManager bindingManager, + IDynamicFormEventHandler formEventHandler, Lazy> validators, - IDateLocalizationServices dateLocalizationServices, - IOrchardServices services, + IDateLocalizationServices dateLocalizationServices, + IOrchardServices services, ICultureAccessor cultureAccessor) { _serializer = serializer; @@ -152,6 +157,90 @@ public IPageOfItems GetSubmissions(string formName = null, int? skip }; } + public Stream ExportSubmissions(string formName = null) { + var stream = new MemoryStream(); + + string GetColumnId(int columnNumber) { + string result = ""; + do { + result = ((char)((columnNumber - 1) % 26 + (int)'A')).ToString() + result; + columnNumber = (columnNumber - 1) / 26; + } while (columnNumber != 0); + return result; + } + + // Create a spreadsheet document. + var spreadsheetDocument = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook); + + // Add a WorkbookPart to the document. + var workbookpart = spreadsheetDocument.AddWorkbookPart(); + workbookpart.Workbook = new Workbook(); + + // Add a WorksheetPart to the WorkbookPart. + var worksheetPart = workbookpart.AddNewPart(); + var sheetData = new SheetData(); + worksheetPart.Worksheet = new Worksheet(sheetData); + + // Add Sheets to the Workbook. + var sheets = spreadsheetDocument.WorkbookPart.Workbook.AppendChild(new Sheets()); + + // Fetch submissions + var query = _submissionRepository.Table; + + if (!String.IsNullOrWhiteSpace(formName)) { + query = query.Where(x => x.FormName == formName); + } + + var submissions = new Orderable(query).Desc(x => x.CreatedUtc).Queryable.ToArray(); + + foreach (var formGroup in submissions.GroupBy(s => s.FormName)) { + // Append a new worksheet and associate it with the workbook. + var sheet = new Sheet() { + Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart), + SheetId = 1, + Name = formGroup.Key + }; + sheets.Append(sheet); + + var data = GenerateDataTable(formGroup); + uint rowIndex = 1; + + var headerRow = new Row { RowIndex = rowIndex }; + sheetData.Append(headerRow); + + for (int i = 0; i < data.Columns.Count; i++) { + var title = data.Columns[i].ToString().CamelFriendly(); + headerRow.Append(new Cell { + CellReference = GetColumnId(i + 1) + rowIndex, + InlineString = new InlineString { Text = new Text(title) }, + DataType = new EnumValue(CellValues.InlineString), + }); + } + + foreach (DataRow dataRow in data.Rows) { + rowIndex++; + var row = new Row { RowIndex = rowIndex }; + sheetData.Append(row); + for (int i = 0; i < data.Columns.Count; i++) { + var value = dataRow[data.Columns[i]]; + row.Append(new Cell { + CellReference = GetColumnId(i + 1) + rowIndex, + InlineString = new InlineString { Text = new Text(value.ToString()) }, + DataType = new EnumValue(CellValues.InlineString), + }); + } + } + } + + workbookpart.Workbook.Save(); + + // Close the document. + spreadsheetDocument.Dispose(); + stream.Seek(0, SeekOrigin.Begin); + + return stream; + } + public void DeleteSubmission(Submission submission) { _submissionRepository.Delete(submission); } @@ -191,10 +280,10 @@ public NameValueCollection ReadElementValues(Form form, IValueProvider valueProv // Collect any remaining form values not handled by any specific element. var requestForm = _services.WorkContext.HttpContext.Request.Form; - var blackList = new[] {"__RequestVerificationToken", "formName", "contentId"}; - foreach (var key in - from string key in requestForm - where !String.IsNullOrWhiteSpace(key) && !blackList.Contains(key) && values[key] == null + var blackList = new[] { "__RequestVerificationToken", "formName", "contentId" }; + foreach (var key in + from string key in requestForm + where !String.IsNullOrWhiteSpace(key) && !blackList.Contains(key) && values[key] == null select key) { values.Add(key, requestForm[key]); @@ -204,13 +293,14 @@ from string key in requestForm } public DataTable GenerateDataTable(IEnumerable submissions) { - var records = submissions.Select(x => Tuple.Create(x, x.ToNameValues())).ToArray(); + var records = submissions.Select(x => System.Tuple.Create(x, x.ToNameValues())).ToArray(); var columnNames = new HashSet(); var dataTable = new DataTable(); - foreach (var key in - from record in records - from string key in record.Item2 where !columnNames.Contains(key) + foreach (var key in + from record in records + from string key in record.Item2 + where !columnNames.Contains(key) where !String.IsNullOrWhiteSpace(key) select key) { columnNames.Add(key); @@ -282,7 +372,7 @@ public ContentItem CreateContentItem(Form form, IValueProvider valueProvider) { if (form.Publication == "Publish" || !contentTypeSettings.Draftable) { _contentManager.Publish(contentItem); } - + return contentItem; } @@ -307,8 +397,8 @@ public void RegisterClientValidationAttributes(FormElement element, RegisterClie } private static void InvokePartBindings( - ContentItem contentItem, - IEnumerable lookup, + ContentItem contentItem, + IEnumerable lookup, PartBindingSettings partBindingSettings, string value) { @@ -348,7 +438,7 @@ private static void InvokeFieldBindings( if (field == null) return; - var fieldBindingDescriptorsQuery = + var fieldBindingDescriptorsQuery = from partBindingDescriptor in lookup where partBindingDescriptor.Part.PartDefinition.Name == partBindingSettings.Name from fieldBindingDescriptor in partBindingDescriptor.FieldBindings @@ -377,4 +467,4 @@ private static bool IsFormElementType(IElementValidator validator, Type elementT return validatorElementType == elementType || validatorElementType.IsAssignableFrom(elementType); } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/IFormService.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/IFormService.cs index 2a90e007647..4e40ed58a34 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/IFormService.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/IFormService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Data; +using System.IO; using System.Web.Mvc; using Orchard.Collections; using Orchard.ContentManagement; @@ -20,6 +21,7 @@ public interface IFormService : IDependency { Submission CreateSubmission(Submission submission); Submission GetSubmission(int id); IPageOfItems GetSubmissions(string formName = null, int? skip = null, int? take = null); + Stream ExportSubmissions(string formName = null); void DeleteSubmission(Submission submission); int DeleteSubmissions(IEnumerable submissionIds); void ReadElementValues(FormElement element, ReadElementValuesContext context); diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/Models/FormSubmissionTokenContext.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/Models/FormSubmissionTokenContext.cs index 870cdb8330c..a61cca42dc7 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/Models/FormSubmissionTokenContext.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/Models/FormSubmissionTokenContext.cs @@ -1,11 +1,13 @@ using System.Collections.Specialized; using System.Web.Mvc; using Orchard.DynamicForms.Elements; +using Orchard.ContentManagement; namespace Orchard.DynamicForms.Services.Models { public class FormSubmissionTokenContext { public Form Form { get; set; } public ModelStateDictionary ModelState { get; set; } public NameValueCollection PostedValues { get; set; } + public ContentItem CreatedContent { get; set; } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Styles/recipebuilderstep-forms.css b/src/Orchard.Web/Modules/Orchard.DynamicForms/Styles/recipebuilderstep-forms.css new file mode 100644 index 00000000000..660a1b0124f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Styles/recipebuilderstep-forms.css @@ -0,0 +1,9 @@ +fieldset.recipe-builder-step-form-submissions table.items { + width: 500px; + margin: 0; +} + +fieldset.recipe-builder-step-form-submissions table.items td, +fieldset.recipe-builder-step-form-submissions table.items thead tr.sub th { + padding: 0 12px; +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Styles/workflows-activity-add-model-error.css b/src/Orchard.Web/Modules/Orchard.DynamicForms/Styles/workflows-activity-add-model-error.css deleted file mode 100644 index 5f282702bb0..00000000000 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Styles/workflows-activity-add-model-error.css +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Styles/workflows-activity-dynamic-form-submitted.css b/src/Orchard.Web/Modules/Orchard.DynamicForms/Styles/workflows-activity-dynamic-form-submitted.css deleted file mode 100644 index 5f282702bb0..00000000000 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Styles/workflows-activity-dynamic-form-submitted.css +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Styles/workflows-activity-dynamic-form-validating.css b/src/Orchard.Web/Modules/Orchard.DynamicForms/Styles/workflows-activity-dynamic-form-validating.css deleted file mode 100644 index 5f282702bb0..00000000000 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Styles/workflows-activity-dynamic-form-validating.css +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Tokens/FormTokens.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Tokens/FormTokens.cs index 68fbdb5c4be..df2f3f50ea4 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Tokens/FormTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Tokens/FormTokens.cs @@ -9,14 +9,18 @@ public void Describe(DescribeContext context) { context.For("FormSubmission", T("Dynamic Form submission"), T("Dynamic Form Submission tokens for use in workflows handling the Dynamic Form Submitted event.")) .Token("Field:*", T("Field:"), T("The posted field value to access."), "Text") .Token("IsValid:*", T("IsValid:"), T("The posted field validation status.")) - ; + .Token("CreatedContent", T("CreatedContent"), T("Id of the Content Item created by the form.")) + .Token("FormName", T("FormName"), T("The name of the form posted.")); } public void Evaluate(EvaluateContext context) { context.For("FormSubmission") .Token(token => token.StartsWith("Field:", StringComparison.OrdinalIgnoreCase) ? token.Substring("Field:".Length) : null, GetFieldValue) .Chain(FilterChainParam, "Text", GetFieldValue) - .Token(token => token.StartsWith("IsValid:", StringComparison.OrdinalIgnoreCase) ? token.Substring("IsValid:".Length) : null, GetFieldValidationStatus); + .Token(token => token.StartsWith("IsValid:", StringComparison.OrdinalIgnoreCase) ? token.Substring("IsValid:".Length) : null, GetFieldValidationStatus) + .Token("CreatedContent", GetCreatedContent) + .Chain("CreatedContent", "Content", GetCreatedContent) + .Token("FormName", GetFormName); } private static Tuple FilterChainParam(string token) { @@ -35,5 +39,13 @@ private string GetFieldValue(string fieldName, FormSubmissionTokenContext contex private object GetFieldValidationStatus(string fieldName, FormSubmissionTokenContext context) { return context.ModelState.IsValidField(fieldName); } + + private object GetCreatedContent(FormSubmissionTokenContext context) { + return context.CreatedContent; + } + + private string GetFormName(FormSubmissionTokenContext context) { + return context.Form.Name; + } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/ValidationRules/EmailAddress.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/ValidationRules/EmailAddress.cs index 0015e8106b8..70a52fb66c0 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/ValidationRules/EmailAddress.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/ValidationRules/EmailAddress.cs @@ -9,7 +9,9 @@ namespace Orchard.DynamicForms.ValidationRules { public class EmailAddress : ValidationRule { public EmailAddress() { RegexOptions = RegexOptions.Singleline | RegexOptions.IgnoreCase; - Pattern = @"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$"; + // From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address + // Retrieved 2018-07-28 + Pattern = @"^[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])?)*$"; } public string Pattern { get; set; } diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/ViewModels/FormExportEntry.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/ViewModels/FormExportEntry.cs new file mode 100644 index 00000000000..d3d1860d23d --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/ViewModels/FormExportEntry.cs @@ -0,0 +1,6 @@ +namespace Orchard.DynamicForms.ViewModels { + public class FormExportEntry { + public string FormName { get; set; } + public bool Export { get; set; } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/AutoLabelScript.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/AutoLabelScript.cshtml new file mode 100644 index 00000000000..75fcf2775a6 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/AutoLabelScript.cshtml @@ -0,0 +1,43 @@ +@using (Script.Foot()) { + +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/BlueprintAdmin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/BlueprintAdmin/Index.cshtml index ffbdbb8be4e..53a8d657288 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/BlueprintAdmin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/BlueprintAdmin/Index.cshtml @@ -32,8 +32,14 @@ @blueprint.ElementTypeName @blueprint.BaseElementTypeName - @Html.ActionLink(T("Edit").Text, "Edit", "BlueprintAdmin", new { id = blueprint.Id, area = "Orchard.DynamicForms" }, null) @T(" | ") - @Html.ActionLink(T("Remove").Text, "Delete", "BlueprintAdmin", new { id = blueprint.Id, area = "Orchard.DynamicForms" }, new { itemprop = "RemoveUrl UnsafeUrl" }) + } diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/EditorTemplates/BuilderSteps/FormSubmissions.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/EditorTemplates/BuilderSteps/FormSubmissions.cshtml new file mode 100644 index 00000000000..bfcb2c06517 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/EditorTemplates/BuilderSteps/FormSubmissions.cshtml @@ -0,0 +1,35 @@ +@model List +@using Orchard.DynamicForms.ViewModels; + +@{ + Style.Include("recipebuilderstep-forms.css"); +} + +
        + + + + + + + + + + @for (int index = 0; index < Model.Count(); index++) { + var entry = Model.ElementAt(index); + + + + + + } + +
        @T("Form") + + @T("Select All") +
        @entry.FormName + + +
        + @Html.Hint(T("Choose the forms to include in the export file")) +
        diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/Button.Design.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/Button.Design.cshtml index 49ca38e05d8..e59290ba4af 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/Button.Design.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/Button.Design.cshtml @@ -4,7 +4,7 @@ var element = (Button)Model.Element; var tagBuilder = TagBuilderExtensions.CreateElementTagBuilder(Model, "button"); - tagBuilder.Attributes["type"] = "submit"; + tagBuilder.Attributes["type"] = "button"; tagBuilder.Attributes["name"] = element.Name; tagBuilder.SetInnerText(element.Text); } diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/EmailField.Design.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/EmailField.Design.cshtml index f16f885b172..6b8fcbe45cf 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/EmailField.Design.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/EmailField.Design.cshtml @@ -8,6 +8,7 @@ tagBuilder.Attributes["type"] = "text"; tagBuilder.Attributes["value"] = element.Value; tagBuilder.Attributes["name"] = element.Name; + tagBuilder.Attributes["placeholder"] = element.Placeholder; } @if (element.ShowLabel) { diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/EmailField.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/EmailField.cshtml index e43fca7d5e1..b623177e875 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/EmailField.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/EmailField.cshtml @@ -9,6 +9,7 @@ tagBuilder.Attributes["type"] = "email"; tagBuilder.Attributes["value"] = Model.ProcessedValue; tagBuilder.Attributes["name"] = Model.ProcessedName; + tagBuilder.Attributes["placeholder"] = Model.ProcessedPlaceholder; tagBuilder.AddClientValidationAttributes((IDictionary)Model.ClientValidationAttributes); if (!ViewData.ModelState.IsValidField(Model.ProcessedName)) { diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/PasswordField.Design.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/PasswordField.Design.cshtml index 4b237e0e762..bf0d9e8d69a 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/PasswordField.Design.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/PasswordField.Design.cshtml @@ -8,6 +8,7 @@ tagBuilder.Attributes["type"] = "password"; tagBuilder.Attributes["value"] = element.Value; tagBuilder.Attributes["name"] = element.Name; + tagBuilder.Attributes["placeholder"] = element.Placeholder; } @if (element.ShowLabel) { diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/PasswordField.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/PasswordField.cshtml index 7e03762ead1..5edf8bf2747 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/PasswordField.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/PasswordField.cshtml @@ -8,6 +8,7 @@ tagBuilder.AddCssClass("text"); tagBuilder.Attributes["type"] = "password"; tagBuilder.Attributes["name"] = Model.ProcessedName; + tagBuilder.Attributes["placeholder"] = Model.ProcessedPlaceholder; tagBuilder.AddClientValidationAttributes((IDictionary)Model.ClientValidationAttributes); if (!ViewData.ModelState.IsValidField(element.Name)) { diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextArea.Design.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextArea.Design.cshtml index 5481c36d880..53f13581ca8 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextArea.Design.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextArea.Design.cshtml @@ -6,6 +6,7 @@ tagBuilder.AddCssClass("text design"); tagBuilder.Attributes["name"] = element.Name; + tagBuilder.Attributes["placeholder"] = element.Placeholder; if (element.Rows != null) { tagBuilder.Attributes["rows"] = element.Rows.ToString(); diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextArea.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextArea.cshtml index af64c27d54a..6c48653ae6b 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextArea.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextArea.cshtml @@ -8,6 +8,7 @@ tagBuilder.AddCssClass("text"); tagBuilder.Attributes["name"] = name; + tagBuilder.Attributes["placeholder"] = Model.ProcessedPlaceholder; tagBuilder.AddClientValidationAttributes((IDictionary)Model.ClientValidationAttributes); if (element.Rows != null) { diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextField.Design.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextField.Design.cshtml index 1d266252d67..7bb3df4b497 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextField.Design.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextField.Design.cshtml @@ -8,6 +8,7 @@ tagBuilder.Attributes["type"] = "text"; tagBuilder.Attributes["value"] = element.Value; tagBuilder.Attributes["name"] = element.Name; + tagBuilder.Attributes["placeholder"] = element.Placeholder; } @if (element.ShowLabel) { diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextField.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextField.cshtml index f0cc0579e5f..706ef654d31 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextField.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/TextField.cshtml @@ -9,6 +9,7 @@ tagBuilder.Attributes["type"] = "text"; tagBuilder.Attributes["value"] = Model.ProcessedValue; tagBuilder.Attributes["name"] = Model.ProcessedName; + tagBuilder.Attributes["placeholder"] = Model.ProcessedPlaceholder; tagBuilder.AddClientValidationAttributes((IDictionary)Model.ClientValidationAttributes); if (!ViewData.ModelState.IsValidField(Model.ProcessedName)) { diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/UrlField.Design.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/UrlField.Design.cshtml index aad86e6c3c0..33bb8123a81 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/UrlField.Design.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/UrlField.Design.cshtml @@ -8,6 +8,7 @@ tagBuilder.Attributes["type"] = "url"; tagBuilder.Attributes["value"] = element.Value; tagBuilder.Attributes["name"] = element.Name; + tagBuilder.Attributes["placeholder"] = element.Placeholder; } @if (element.ShowLabel) { diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/UrlField.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/UrlField.cshtml index a205053dc21..5fab6d6e1c7 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/UrlField.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/Elements/UrlField.cshtml @@ -9,6 +9,7 @@ tagBuilder.Attributes["type"] = "url"; tagBuilder.Attributes["value"] = Model.ProcessedValue; tagBuilder.Attributes["name"] = Model.ProcessedName; + tagBuilder.Attributes["placeholder"] = Model.ProcessedPlaceholder; tagBuilder.AddClientValidationAttributes((IDictionary)Model.ClientValidationAttributes); if (!ViewData.ModelState.IsValidField(Model.ProcessedName)) { diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/SubmissionAdmin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/SubmissionAdmin/Index.cshtml index 18b41f3ea98..7f1ff3ac745 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/SubmissionAdmin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Views/SubmissionAdmin/Index.cshtml @@ -2,7 +2,6 @@ @using Orchard.Utility.Extensions @model Orchard.DynamicForms.ViewModels.SubmissionsIndexViewModel @{ - Style.Include("forms-admin.css", "forms-admin.min.css"); // TODO: Shouldn't this be a Style.Require()? Script.Require("ShapesBase"); Layout.Title = T("Submissions for {0}", Model.FormName); } @@ -14,6 +13,9 @@ dataColumns.Add(Model.Submissions.Columns[i]); } } +
        + @Html.ActionLink(T("Export").Text, "Export", "SubmissionAdmin", new { id = Model.FormName, area = "Orchard.DynamicForms" }, new { @class = "button primaryAction" }) +
        @using (Html.BeginFormAntiForgeryPost()) {
        @@ -42,8 +44,14 @@ @dataRow[dataColumn] } - @Html.ActionLink(T("Details").Text, "Details", "SubmissionAdmin", new { id = id, area = "Orchard.DynamicForms" }, null) @T(" | ") - @Html.ActionLink(T("Remove").Text, "Delete", "SubmissionAdmin", new { id = id, area = "Orchard.DynamicForms" }, new { itemprop = "RemoveUrl UnsafeUrl" }) + } diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Web.config b/src/Orchard.Web/Modules/Orchard.DynamicForms/Web.config index 3ea3828a353..a80a92b2458 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Web.config +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Web.config @@ -7,7 +7,7 @@ - + @@ -21,14 +21,17 @@ + + + - + - + @@ -38,25 +41,41 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/packages.config b/src/Orchard.Web/Modules/Orchard.DynamicForms/packages.config index 1ea27eef99b..d4d34828332 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/packages.config +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/packages.config @@ -1,8 +1,12 @@  - - - - - + + + + + + + + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Activities/EmailActivity.cs b/src/Orchard.Web/Modules/Orchard.Email/Activities/EmailActivity.cs index ccb8f16ec62..b6f13bebd82 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Activities/EmailActivity.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Activities/EmailActivity.cs @@ -3,6 +3,7 @@ using Orchard.Environment.Extensions; using Orchard.Events; using Orchard.Localization; +using Orchard.Logging; using Orchard.Messaging.Services; using Orchard.Workflows.Models; using Orchard.Workflows.Services; @@ -16,6 +17,7 @@ public interface IJobsQueueService : IEventHandler { public class EmailActivity : Task { private readonly IMessageService _messageService; private readonly IJobsQueueService _jobsQueueService; + public ILogger Logger { get; set; } public EmailActivity( IMessageService messageService, @@ -23,13 +25,14 @@ IJobsQueueService jobsQueueService ) { _messageService = messageService; _jobsQueueService = jobsQueueService; + Logger = NullLogger.Instance; T = NullLocalizer.Instance; } public Localizer T { get; set; } public override IEnumerable GetPossibleOutcomes(WorkflowContext workflowContext, ActivityContext activityContext) { - return new[] { T("Done") }; + return new[] { T("Done"), T("Failed") }; } public override string Form { @@ -57,6 +60,7 @@ public override IEnumerable Execute(WorkflowContext workflowCon var replyTo = activityContext.GetState("ReplyTo"); var bcc = activityContext.GetState("Bcc"); var cc = activityContext.GetState("CC"); + var notifyReadEmail = activityContext.GetState("NotifyReadEmail"); var parameters = new Dictionary { {"Subject", subject}, @@ -64,20 +68,27 @@ public override IEnumerable Execute(WorkflowContext workflowCon {"Recipients", recipients}, {"ReplyTo", replyTo}, {"Bcc", bcc}, - {"CC", cc} + {"CC", cc}, + {"NotifyReadEmail", notifyReadEmail } }; - var queued = activityContext.GetState("Queued"); - - if (!queued) { - _messageService.Send(SmtpMessageChannel.MessageType, parameters); + if (string.IsNullOrWhiteSpace(recipients)) { + Logger.Error("Email message doesn't have any recipient for Workflow {0}", workflowContext.Record.WorkflowDefinitionRecord.Name); + yield return T("Failed"); } else { - var priority = activityContext.GetState("Priority"); - _jobsQueueService.Enqueue("IMessageService.Send", new { type = SmtpMessageChannel.MessageType, parameters = parameters }, priority); - } + var queued = activityContext.GetState("Queued"); - yield return T("Done"); + if (!queued) { + _messageService.Send(SmtpMessageChannel.MessageType, parameters); + } + else { + var priority = activityContext.GetState("Priority"); + _jobsQueueService.Enqueue("IMessageService.Send", new { type = SmtpMessageChannel.MessageType, parameters = parameters }, priority); + } + + yield return T("Done"); + } } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Controllers/EmailAdminController.cs b/src/Orchard.Web/Modules/Orchard.Email/Controllers/EmailAdminController.cs index 9c3bc605d86..940b3ac4597 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Controllers/EmailAdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Controllers/EmailAdminController.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Web.Hosting; using System.Web.Mvc; using Orchard.ContentManagement; using Orchard.Email.Models; @@ -29,8 +28,7 @@ public ActionResult TestSettings(TestSmtpSettings testSettings) { ILogger logger = null; try { var fakeLogger = new FakeLogger(); - var smtpChannelComponent = _smtpChannel as Component; - if (smtpChannelComponent != null) { + if (_smtpChannel is Component smtpChannelComponent) { logger = smtpChannelComponent.Logger; smtpChannelComponent.Logger = fakeLogger; } @@ -38,14 +36,17 @@ public ActionResult TestSettings(TestSmtpSettings testSettings) { // Temporarily update settings so that the test will actually use the specified host, port, etc. var smtpSettings = _orchardServices.WorkContext.CurrentSite.As(); - smtpSettings.Address = testSettings.From; + smtpSettings.FromAddress = testSettings.FromAddress; + smtpSettings.FromName = testSettings.FromName; + smtpSettings.ReplyTo = testSettings.ReplyTo; smtpSettings.Host = testSettings.Host; smtpSettings.Port = testSettings.Port; - smtpSettings.EnableSsl = testSettings.EnableSsl; + smtpSettings.AutoSelectEncryption = testSettings.AutoSelectEncryption; + smtpSettings.EncryptionMethod = testSettings.EncryptionMethod; smtpSettings.RequireCredentials = testSettings.RequireCredentials; - smtpSettings.UseDefaultCredentials = testSettings.UseDefaultCredentials; smtpSettings.UserName = testSettings.UserName; smtpSettings.Password = testSettings.Password; + smtpSettings.ListUnsubscribe = testSettings.ListUnsubscribe; if (!smtpSettings.IsValid()) { fakeLogger.Error("Invalid settings."); @@ -57,7 +58,7 @@ public ActionResult TestSettings(TestSmtpSettings testSettings) { }); } - if (!String.IsNullOrEmpty(fakeLogger.Message)) { + if (!string.IsNullOrEmpty(fakeLogger.Message)) { return Json(new { error = fakeLogger.Message }); } @@ -67,12 +68,11 @@ public ActionResult TestSettings(TestSmtpSettings testSettings) { return Json(new { error = e.Message }); } finally { - var smtpChannelComponent = _smtpChannel as Component; - if (smtpChannelComponent != null) { + if (_smtpChannel is Component smtpChannelComponent) { smtpChannelComponent.Logger = logger; } - // Undo the temporarily changed smtp settings. + // Undo the temporarily changed SMTP settings. _orchardServices.TransactionManager.Cancel(); } } @@ -80,25 +80,25 @@ public ActionResult TestSettings(TestSmtpSettings testSettings) { private class FakeLogger : ILogger { public string Message { get; set; } - public bool IsEnabled(LogLevel level) { - return true; - } + public bool IsEnabled(LogLevel level) => true; - public void Log(LogLevel level, Exception exception, string format, params object[] args) { + public void Log(LogLevel level, Exception exception, string format, params object[] args) => Message = exception == null ? format : exception.Message; - } } public class TestSmtpSettings { - public string From { get; set; } + public string FromAddress { get; set; } + public string FromName { get; set; } + public string ReplyTo { get; set; } public string Host { get; set; } public int Port { get; set; } - public bool EnableSsl { get; set; } + public SmtpEncryptionMethod EncryptionMethod { get; set; } + public bool AutoSelectEncryption { get; set; } public bool RequireCredentials { get; set; } - public bool UseDefaultCredentials { get; set; } public string UserName { get; set; } public string Password { get; set; } public string To { get; set; } + public string ListUnsubscribe { get; set; } } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Forms/EmailForm.cs b/src/Orchard.Web/Modules/Orchard.Email/Forms/EmailForm.cs index 9e790159fb5..90b69a8f328 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Forms/EmailForm.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Forms/EmailForm.cs @@ -63,7 +63,12 @@ public void Describe(DescribeContext context) { Id: "Body", Name: "Body", Title: T("Body"), Description: T("The body of the email message."), - Classes: new[] {"tokenized"}) + Classes: new[] {"tokenized"}), + _NotifyReadEmail: New.Checkbox( + Id: "NotifyReadEmail", Name: "NotifyReadEmail", + Title: T("Notify email read"), + Checked: false, Value: "true", + Description: T("Notify when email sent gets read by the recipient.")) )); if (jobsQueueEnabled) { diff --git a/src/Orchard.Web/Modules/Orchard.Email/Handlers/SmtpSettingsPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Email/Handlers/SmtpSettingsPartHandler.cs index e1160ad4686..be2d200102b 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Handlers/SmtpSettingsPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Handlers/SmtpSettingsPartHandler.cs @@ -1,12 +1,12 @@ using System; +using System.Configuration; using System.Text; using Orchard.ContentManagement; -using Orchard.Email.Models; using Orchard.ContentManagement.Handlers; +using Orchard.Email.Models; using Orchard.Localization; using Orchard.Logging; using Orchard.Security; -using System.Configuration; namespace Orchard.Email.Handlers { public class SmtpSettingsPartHandler : ContentHandler { @@ -24,7 +24,8 @@ public SmtpSettingsPartHandler(IEncryptionService encryptionService) { OnInitializing((context, part) => { part.Port = 25; part.RequireCredentials = false; - part.EnableSsl = false; + part.AutoSelectEncryption = true; + part.EncryptionMethod = SmtpEncryptionMethod.None; }); } diff --git a/src/Orchard.Web/Modules/Orchard.Email/Migrations.cs b/src/Orchard.Web/Modules/Orchard.Email/Migrations.cs index 0409097b9dd..5fa5cbbf60a 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Migrations.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Migrations.cs @@ -1,11 +1,37 @@ -using Orchard.Data.Migration; +using System.Linq; +using System.Xml; +using Orchard.ContentManagement; +using Orchard.Data.Migration; +using Orchard.Email.Models; namespace Orchard.Email { public class Migrations : DataMigrationImpl { + private readonly IContentManager _contentManager; + public Migrations(IContentManager contentManager) => _contentManager = contentManager; + // The first migration without any content should not exist but it has been deployed so we need to keep it. + public int Create() => 1; - public int Create() { + public int UpdateFrom1() { + // Migrate existing SmtpSettingPart.Address because we rename it to FromAddress. + var siteSettingsItem = _contentManager.Query(contentTypeNames: "Site") + .Slice(1) + .SingleOrDefault(); - return 1; + var siteSettingsRecord = siteSettingsItem?.Record; + + if (siteSettingsRecord != null) { + var xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(siteSettingsRecord.Data); + + var smtpSettingNode = xmlDoc.SelectSingleNode("//SmtpSettingsPart"); + if (smtpSettingNode != null) { + var smtpSettingsPart = siteSettingsItem.As(); + smtpSettingsPart.FromAddress = smtpSettingNode.Attributes["Address"]?.Value; + } + } + + return 2; } } -} \ No newline at end of file +} + diff --git a/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs b/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs index 8c588ce91c3..190b5a5ce3c 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs @@ -6,9 +6,11 @@ public class EmailMessage { public string Body { get; set; } public string Recipients { get; set; } public string ReplyTo { get; set; } - public string From { get; set; } + public string FromAddress { get; set; } + public string FromName { get; set; } public string Bcc { get; set; } public string Cc { get; set; } + public bool NotifyReadEmail { get; set; } /// /// IEnumerable of strings representing attachments paths /// diff --git a/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpEncryptionMethod.cs b/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpEncryptionMethod.cs new file mode 100644 index 00000000000..64ed03aa427 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpEncryptionMethod.cs @@ -0,0 +1,10 @@ +namespace Orchard.Email.Models { + /// + /// Represents an enumeration for mail encryption methods. + /// + public enum SmtpEncryptionMethod { + None = 0, + SslTls = 1, + StartTls = 2 + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPart.cs index 3eb75d95291..61ce46a91de 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPart.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPart.cs @@ -1,76 +1,104 @@ -using System.Configuration; +using System; +using System.Configuration; using System.Net.Configuration; using Orchard.ContentManagement; -using System; using Orchard.ContentManagement.Utilities; namespace Orchard.Email.Models { public class SmtpSettingsPart : ContentPart { private readonly ComputedField _password = new ComputedField(); - public ComputedField PasswordField { - get { return _password; } + public ComputedField PasswordField => _password; + + public string FromAddress { + get => this.Retrieve(x => x.FromAddress); + set => this.Store(x => x.FromAddress, value); + } + + public string FromName { + get => this.Retrieve(x => x.FromName); + set => this.Store(x => x.FromName, value); } - public string Address { - get { return this.Retrieve(x => x.Address); } - set { this.Store(x => x.Address, value); } + public string ReplyTo { + get => this.Retrieve(x => x.ReplyTo); + set => this.Store(x => x.ReplyTo, value); } private readonly LazyField _addressPlaceholder = new LazyField(); - internal LazyField AddressPlaceholderField { get { return _addressPlaceholder; } } - public string AddressPlaceholder { get { return _addressPlaceholder.Value; } } + internal LazyField AddressPlaceholderField => _addressPlaceholder; + public string AddressPlaceholder => _addressPlaceholder.Value; public string Host { - get { return this.Retrieve(x => x.Host); } - set { this.Store(x => x.Host, value); } + get => this.Retrieve(x => x.Host); + set => this.Store(x => x.Host, value); } public int Port { - get { return this.Retrieve(x => x.Port, 25); } - set { this.Store(x => x.Port, value); } + get => this.Retrieve(x => x.Port, 25); + set => this.Store(x => x.Port, value); } - public bool EnableSsl { - get { return this.Retrieve(x => x.EnableSsl); } - set { this.Store(x => x.EnableSsl, value); } + [Obsolete("Use " + nameof(AutoSelectEncryption) + " and/or "+ nameof(EncryptionMethod) + " instead.")] + public bool EnableSsl => this.Retrieve(x => x.EnableSsl); + + public SmtpEncryptionMethod EncryptionMethod { +#pragma warning disable CS0618 // Type or member is obsolete + // Reading EnableSsl is necessary to keep the correct settings during the upgrade to MailKit. + get { return this.Retrieve(x => x.EncryptionMethod, EnableSsl ? (Port == 587 ? SmtpEncryptionMethod.StartTls : SmtpEncryptionMethod.SslTls) : SmtpEncryptionMethod.None); } +#pragma warning restore CS0618 // Type or member is obsolete + set { this.Store(x => x.EncryptionMethod, value); } } - public bool RequireCredentials { - get { return this.Retrieve(x => x.RequireCredentials); } - set { this.Store(x => x.RequireCredentials, value); } + public bool AutoSelectEncryption { +#pragma warning disable CS0618 // Type or member is obsolete + // Reading EnableSsl is necessary to keep the correct settings during the upgrade to MailKit. + get { return this.Retrieve(x => x.AutoSelectEncryption, !EnableSsl); } +#pragma warning restore CS0618 // Type or member is obsolete + set { this.Store(x => x.AutoSelectEncryption, value); } } - public bool UseDefaultCredentials { - get { return this.Retrieve(x => x.UseDefaultCredentials); } - set { this.Store(x => x.UseDefaultCredentials, value); } + public bool RequireCredentials { + get => this.Retrieve(x => x.RequireCredentials); + set => this.Store(x => x.RequireCredentials, value); } public string UserName { - get { return this.Retrieve(x => x.UserName); } - set { this.Store(x => x.UserName, value); } + get => this.Retrieve(x => x.UserName); + set => this.Store(x => x.UserName, value); } public string Password { - get { return _password.Value; } - set { _password.Value = value; } + get => _password.Value; + set => _password.Value = value; + } + + // Hotmail only supports the mailto:link. When a user clicks on the 'unsubscribe' option in Hotmail. + // Hotmail tries to read the mailto:link in the List-Unsubscribe header. + // If the mailto:link is missing, it moves all the messages to the Junk folder. + // The mailto:link is supported by Gmail, Hotmail, Yahoo, AOL, ATT, Time Warner and Comcast; + // European ISPs such as GMX, Libero, Ziggo, Orange, BTInternet; Russian ISPs such as mail.ru and Yandex; + // and the Chinese domains qq.com, naver.com etc. So most ISPs support (and prefer) mailto:link. + public string ListUnsubscribe { + get => this.Retrieve(x => x.ListUnsubscribe); + set => this.Store(x => x.ListUnsubscribe, value); } public bool IsValid() { var section = (SmtpSection)ConfigurationManager.GetSection("system.net/mailSettings/smtp"); - if (section != null && !String.IsNullOrWhiteSpace(section.Network.Host)) { + if (section != null && !string.IsNullOrWhiteSpace(section.Network.Host)) { return true; } - if (String.IsNullOrWhiteSpace(Address)) { + if (string.IsNullOrWhiteSpace(FromAddress)) { return false; } - if (!String.IsNullOrWhiteSpace(Host) && Port == 0) { + if (!string.IsNullOrWhiteSpace(Host) && Port == 0) { return false; } return true; } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Email/Module.txt b/src/Orchard.Web/Modules/Orchard.Email/Module.txt index 259382133bb..3b85a2743fe 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Email/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: The Email Messaging module adds Email sending functionalities. Features: Orchard.Email: diff --git a/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj b/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj index a629328ae4f..fed4b0b6ae9 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj +++ b/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj @@ -12,8 +12,8 @@ Properties Orchard.Email Orchard.Email - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,9 @@ + + + true @@ -49,49 +52,60 @@ false + + ..\..\..\packages\Portable.BouncyCastle.1.9.0\lib\net40\BouncyCastle.Crypto.dll + + + ..\..\..\packages\MailKit.3.1.1\lib\net48\MailKit.dll + + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - - ..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True + + ..\..\..\packages\MimeKit.3.1.1\lib\net48\MimeKit.dll + + + ..\..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll + + ..\..\..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + False + + + - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll + @@ -103,6 +117,7 @@ + @@ -116,8 +131,7 @@ - - + @@ -126,12 +140,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {642a49d7-8752-4177-80d6-bfbbcfad3de0} @@ -148,9 +162,6 @@ - - - @@ -161,7 +172,7 @@ - + 10.0 @@ -191,7 +202,7 @@ --> - + @@ -205,7 +216,7 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False diff --git a/src/Orchard.Web/Modules/Orchard.Email/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Email/Properties/AssemblyInfo.cs index 09a8accf407..bf8dd545fa4 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessagingChannel.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessagingChannel.cs index 6131c8b4586..4a1a26c4f5e 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessagingChannel.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessagingChannel.cs @@ -53,7 +53,7 @@ public void SendMessage(MessageContext context) { smtpClient.EnableSsl = smtpSettings.EnableSsl; smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network; - context.MailMessage.From = new MailAddress(smtpSettings.Address); + context.MailMessage.From = new MailAddress(smtpSettings.FromAddress); context.MailMessage.IsBodyHtml = !String.IsNullOrWhiteSpace(context.MailMessage.Body) && context.MailMessage.Body.Contains("<") && context.MailMessage.Body.Contains(">"); try { diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/MissingSettingsBanner.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/MissingSettingsBanner.cs index 7e22702617b..e80f239e2ff 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Services/MissingSettingsBanner.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/MissingSettingsBanner.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Net.Mail; using System.Web.Mvc; using Orchard.ContentManagement; using Orchard.Email.Models; @@ -24,8 +23,8 @@ public IEnumerable GetNotifications() { if (smtpSettings == null || !smtpSettings.IsValid()) { var urlHelper = new UrlHelper(workContext.HttpContext.Request.RequestContext); - var url = urlHelper.Action("Email", "Admin", new {Area = "Settings"}); - yield return new NotifyEntry {Message = T("The SMTP settings need to be configured.", url), Type = NotifyType.Warning}; + var url = urlHelper.Action("Email", "Admin", new { Area = "Settings" }); + yield return new NotifyEntry { Message = T("The SMTP settings need to be configured.", url), Type = NotifyType.Warning }; } } } diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs index bb2dc3c6f30..d8c32ec1af0 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs @@ -1,16 +1,18 @@ using System; using System.Collections.Generic; using System.Configuration; -using System.Net; +using System.IO; +using System.Linq; using System.Net.Configuration; using System.Net.Mail; using System.Web.Mvc; +using MailKit.Security; +using MimeKit; using Orchard.ContentManagement; using Orchard.DisplayManagement; -using Orchard.Logging; using Orchard.Email.Models; -using System.Linq; -using System.IO; +using Orchard.Logging; +using SmtpClient = MailKit.Net.Smtp.SmtpClient; namespace Orchard.Email.Services { public class SmtpMessageChannel : Component, ISmtpChannel, IDisposable { @@ -51,13 +53,18 @@ public void Process(IDictionary parameters) { Subject = Read(parameters, "Subject"), Recipients = Read(parameters, "Recipients"), ReplyTo = Read(parameters, "ReplyTo"), - From = Read(parameters, "From"), + FromAddress = Read(parameters, "FromAddress"), + FromName = Read(parameters, "FromName"), Bcc = Read(parameters, "Bcc"), Cc = Read(parameters, "CC"), - Attachments = (IEnumerable)(parameters.ContainsKey("Attachments") ? parameters["Attachments"] : new List()) + NotifyReadEmail = bool.TryParse(Read(parameters, "NotifyReadEmail"), out var notify) && notify, + Attachments = (IEnumerable)(parameters.ContainsKey("Attachments") + ? parameters["Attachments"] + : new List() + ) }; - if (emailMessage.Recipients.Length == 0) { + if (string.IsNullOrWhiteSpace(emailMessage.Recipients)) { Logger.Error("Email message doesn't have any recipient"); return; } @@ -67,69 +74,61 @@ public void Process(IDictionary parameters) { Content = new MvcHtmlString(emailMessage.Body) })); - var mailMessage = new MailMessage { + var mailMessage = new MimeMessage { Subject = emailMessage.Subject, - Body = _shapeDisplay.Display(template), - IsBodyHtml = true + }; + var mailBodyBuilder = new BodyBuilder { + HtmlBody = _shapeDisplay.Display(template), }; - if (parameters.ContainsKey("Message")) { + if (parameters.TryGetValue("Message", out var possiblyMailMessage) && possiblyMailMessage is MailMessage legacyMessage) { // A full message object is provided by the sender. + if (!String.IsNullOrWhiteSpace(legacyMessage.Subject)) { + mailMessage.Subject = legacyMessage.Subject; + } - var oldMessage = mailMessage; - mailMessage = (MailMessage)parameters["Message"]; - - if (String.IsNullOrWhiteSpace(mailMessage.Subject)) - mailMessage.Subject = oldMessage.Subject; + if (!String.IsNullOrWhiteSpace(legacyMessage.Body)) { + mailBodyBuilder.TextBody = legacyMessage.IsBodyHtml ? null : legacyMessage.Body; + mailBodyBuilder.HtmlBody = legacyMessage.IsBodyHtml ? legacyMessage.Body : null; + } + } - if (String.IsNullOrWhiteSpace(mailMessage.Body)) { - mailMessage.Body = oldMessage.Body; - mailMessage.IsBodyHtml = oldMessage.IsBodyHtml; + foreach (var attachmentPath in emailMessage.Attachments) { + if (File.Exists(attachmentPath)) { + mailBodyBuilder.Attachments.Add(attachmentPath); + } + else { + throw new FileNotFoundException(T("One or more attachments not found.").Text); } } + mailMessage.Body = mailBodyBuilder.ToMessageBody(); + try { + mailMessage.To.AddRange(ParseRecipients(emailMessage.Recipients)); - foreach (var recipient in ParseRecipients(emailMessage.Recipients)) { - mailMessage.To.Add(new MailAddress(recipient)); - } + mailMessage.Cc.AddRange(ParseRecipients(emailMessage.Cc)); - if (!String.IsNullOrWhiteSpace(emailMessage.Cc)) { - foreach (var recipient in ParseRecipients(emailMessage.Cc)) { - mailMessage.CC.Add(new MailAddress(recipient)); - } - } + mailMessage.Bcc.AddRange(ParseRecipients(emailMessage.Bcc)); - if (!String.IsNullOrWhiteSpace(emailMessage.Bcc)) { - foreach (var recipient in ParseRecipients(emailMessage.Bcc)) { - mailMessage.Bcc.Add(new MailAddress(recipient)); - } - } + var fromAddress = MailboxAddress.Parse( + // "From" address precendence: Current email message > site settings > configuration. + string.IsNullOrWhiteSpace(emailMessage.FromAddress) + ? string.IsNullOrWhiteSpace(_smtpSettings.FromAddress) + ? ((SmtpSection)ConfigurationManager.GetSection("system.net/mailSettings/smtp")).From + : _smtpSettings.FromAddress + : emailMessage.FromAddress); + fromAddress.Name = string.IsNullOrWhiteSpace(emailMessage.FromName) ? _smtpSettings.FromName : emailMessage.FromName; + mailMessage.From.Add(fromAddress); - if (!String.IsNullOrWhiteSpace(emailMessage.From)) { - mailMessage.From = new MailAddress(emailMessage.From); - } - else { - // Take 'From' address from site settings or web.config. - mailMessage.From = !String.IsNullOrWhiteSpace(_smtpSettings.Address) - ? new MailAddress(_smtpSettings.Address) - : new MailAddress(((SmtpSection)ConfigurationManager.GetSection("system.net/mailSettings/smtp")).From); - } + mailMessage.ReplyTo.AddRange(ParseRecipients(string.IsNullOrWhiteSpace(emailMessage.ReplyTo) + ? _smtpSettings.ReplyTo + : emailMessage.ReplyTo)); - if (!String.IsNullOrWhiteSpace(emailMessage.ReplyTo)) { - foreach (var recipient in ParseRecipients(emailMessage.ReplyTo)) { - mailMessage.ReplyToList.Add(new MailAddress(recipient)); - } + if (emailMessage.NotifyReadEmail) { + mailMessage.Headers.Add("Disposition-Notification-To", mailMessage.From.ToString()); } - foreach (var attachmentPath in emailMessage.Attachments) { - if (File.Exists(attachmentPath)) { - mailMessage.Attachments.Add(new Attachment(attachmentPath)); - } - else { - throw new FileNotFoundException(T("One or more attachments not found.").Text); - } - } _smtpClientField.Value.Send(mailMessage); } catch (Exception e) { @@ -138,26 +137,56 @@ public void Process(IDictionary parameters) { } private SmtpClient CreateSmtpClient() { + var smtpConfiguration = new { + _smtpSettings.Host, + _smtpSettings.Port, + _smtpSettings.EncryptionMethod, + _smtpSettings.AutoSelectEncryption, + _smtpSettings.RequireCredentials, + _smtpSettings.UserName, + _smtpSettings.Password, + }; // If no properties are set in the dashboard, use the web.config value. if (String.IsNullOrWhiteSpace(_smtpSettings.Host)) { - return new SmtpClient(); - } + var smtpSection = (SmtpSection)ConfigurationManager.GetSection("system.net/mailSettings/smtp"); + if (smtpSection.DeliveryMethod != SmtpDeliveryMethod.Network) { + throw new NotSupportedException($"Only the {SmtpDeliveryMethod.Network} delivery method is supported, but " + + $"{smtpSection.DeliveryMethod} delivery method is configured. Please check your Web.config."); + } - var smtpClient = new SmtpClient { - UseDefaultCredentials = _smtpSettings.RequireCredentials && _smtpSettings.UseDefaultCredentials - }; + smtpConfiguration = new { + smtpSection.Network.Host, + smtpSection.Network.Port, + EncryptionMethod = smtpSection.Network.EnableSsl ? SmtpEncryptionMethod.SslTls : SmtpEncryptionMethod.None, + AutoSelectEncryption = !smtpSection.Network.EnableSsl, + RequireCredentials = smtpSection.Network.DefaultCredentials || !String.IsNullOrWhiteSpace(smtpSection.Network.UserName), + smtpSection.Network.UserName, + smtpSection.Network.Password, + }; + } - if (!smtpClient.UseDefaultCredentials && !String.IsNullOrWhiteSpace(_smtpSettings.UserName)) { - smtpClient.Credentials = new NetworkCredential(_smtpSettings.UserName, _smtpSettings.Password); + var secureSocketOptions = SecureSocketOptions.Auto; + if (!smtpConfiguration.AutoSelectEncryption) { + switch (smtpConfiguration.EncryptionMethod) { + case SmtpEncryptionMethod.SslTls: + secureSocketOptions = SecureSocketOptions.SslOnConnect; + break; + case SmtpEncryptionMethod.StartTls: + secureSocketOptions = SecureSocketOptions.StartTls; + break; + default: + secureSocketOptions = SecureSocketOptions.None; + break; + } } - if (_smtpSettings.Host != null) { - smtpClient.Host = _smtpSettings.Host; + var smtpClient = new SmtpClient(); + smtpClient.Connect(smtpConfiguration.Host, smtpConfiguration.Port, secureSocketOptions); + + if (smtpConfiguration.RequireCredentials) { + smtpClient.Authenticate(smtpConfiguration.UserName, smtpConfiguration.Password); } - smtpClient.Port = _smtpSettings.Port; - smtpClient.EnableSsl = _smtpSettings.EnableSsl; - smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network; return smtpClient; } @@ -165,8 +194,16 @@ private string Read(IDictionary dictionary, string key) { return dictionary.ContainsKey(key) ? dictionary[key] as string : null; } - private IEnumerable ParseRecipients(string recipients) { - return recipients.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); + private IEnumerable ParseRecipients(string recipients) { + return recipients?.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) + .SelectMany(address => { + if (MailboxAddress.TryParse(address, out var mailboxAddress)) { + return new[] { mailboxAddress }; + } + + Logger.Error("Invalid email address: {0}", address); + return Enumerable.Empty(); + }) ?? Enumerable.Empty(); } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Email/Styles/workflows-activity-sendemail.css b/src/Orchard.Web/Modules/Orchard.Email/Styles/workflows-activity-send-email.css similarity index 100% rename from src/Orchard.Web/Modules/Orchard.Email/Styles/workflows-activity-sendemail.css rename to src/Orchard.Web/Modules/Orchard.Email/Styles/workflows-activity-send-email.css diff --git a/src/Orchard.Web/Modules/Orchard.Email/Styles/workflows-activity-sendemaildeprecated.css b/src/Orchard.Web/Modules/Orchard.Email/Styles/workflows-activity-sendemaildeprecated.css deleted file mode 100644 index b10cd302c81..00000000000 --- a/src/Orchard.Web/Modules/Orchard.Email/Styles/workflows-activity-sendemaildeprecated.css +++ /dev/null @@ -1,17 +0,0 @@ -.envelope { - width: 36px; - height: 36px; - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAaCAYAAADWm14/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAARhJREFUSEvtlkEORTAQhnsnSxsre+dwBCdwBidwAyewl0jsbJ3Ahsi8jvfK6JsnqGLxFp/IaGf+jr9NBQDcChu8kumlbVsIggAcx7GK53mAtRYChmEQURSxE2wQhiF0XTcL6PteXLF6xacLD+oAkmUZO9gGaZrKkpoJkSRJ2AlnEsexLDXXXAhAbIrQiyPjA01YFIV8fQfLsmQTmJDn+ZS/qqqlCdUuoArPMiY1HIId/toFdBu6rgt1XcuweTfoqpumAd/3x/iqAAV16t5zQj/t9B22SQAZ+DMRxxbhmwUoaFLaSor+69bE7haAcGZS3/aa95AABTWWzlbDGglAaALT+YcSmPIX8DwBj7iQyC7cdym9EzZ4HSBeOGnowJmFUWAAAAAASUVORK5CYII='); - background-repeat: no-repeat; - background-position: center; -} - -.toolbox-task.toolbox-send-email-deprecated { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAaCAYAAADWm14/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAARhJREFUSEvtlkEORTAQhnsnSxsre+dwBCdwBidwAyewl0jsbJ3Ahsi8jvfK6JsnqGLxFp/IaGf+jr9NBQDcChu8kumlbVsIggAcx7GK53mAtRYChmEQURSxE2wQhiF0XTcL6PteXLF6xacLD+oAkmUZO9gGaZrKkpoJkSRJ2AlnEsexLDXXXAhAbIrQiyPjA01YFIV8fQfLsmQTmJDn+ZS/qqqlCdUuoArPMiY1HIId/toFdBu6rgt1XcuweTfoqpumAd/3x/iqAAV16t5zQj/t9B22SQAZ+DMRxxbhmwUoaFLaSor+69bE7haAcGZS3/aa95AABTWWzlbDGglAaALT+YcSmPIX8DwBj7iQyC7cdym9EzZ4HSBeOGnowJmFUWAAAAAASUVORK5CYII='); - background-repeat: no-repeat; - background-position: 5px 5px; -} - -.toolbox-task.toolbox-send-email-deprecated div { - margin-left: 36px; -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Views/Activity-SendEmailDeprecated.cshtml b/src/Orchard.Web/Modules/Orchard.Email/Views/Activity-SendEmailDeprecated.cshtml deleted file mode 100644 index 24b2670a540..00000000000 --- a/src/Orchard.Web/Modules/Orchard.Email/Views/Activity-SendEmailDeprecated.cshtml +++ /dev/null @@ -1,7 +0,0 @@ -@using Orchard.Utility.Extensions - -
        -
        - @*@name.CamelFriendly()*@ -
        - diff --git a/src/Orchard.Web/Modules/Orchard.Email/Views/EditorTemplates/Parts/SmtpSettings.cshtml b/src/Orchard.Web/Modules/Orchard.Email/Views/EditorTemplates/Parts/SmtpSettings.cshtml index effc28c508a..721e0dcb59b 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Views/EditorTemplates/Parts/SmtpSettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Email/Views/EditorTemplates/Parts/SmtpSettings.cshtml @@ -1,17 +1,27 @@ -@using System.Net.Mail +@using Orchard.Email.Models +@using System.Net.Mail @model Orchard.Email.Models.SmtpSettingsPart @{ var smtpClient = new SmtpClient(); } -
        @T("Email")
        - - @Html.TextBoxFor(m => m.Address, new { @class = "text medium", placeholder = Model.AddressPlaceholder }) - @Html.ValidationMessage("Address", "*") + + @Html.TextBoxFor(m => m.FromAddress, new { @class = "text medium", placeholder = Model.AddressPlaceholder }) + @Html.ValidationMessage("FromAddress", "*") @T("The default email address to use as a sender.")
        +
        + + @Html.TextBoxFor(m => m.FromName, new { @class = "text medium" }) + @T("The default value to use as a sender name.") +
        +
        + + @Html.TextBoxFor(m => m.ReplyTo, new { @class = "text medium" }) + @T("The default email address to use for reply to") +
        @Html.TextBoxFor(m => m.Host, new { placeholder = smtpClient.Host, @class = "text medium" }) @@ -20,51 +30,62 @@
        - @Html.TextBoxFor(m => m.Port, new { placeholder = smtpClient.Port, @class = "text small" }) + @Html.TextBoxFor(m => m.Port, new { type = "number", placeholder = smtpClient.Port, min = 1, max = 65535 }) @Html.ValidationMessage("Port", "*") @T("The SMTP server port, usually 25.")
        - @Html.EditorFor(m => m.EnableSsl) - - @Html.ValidationMessage("EnableSsl", "*") - @T("Check if the SMTP server requires SSL communications.") + + + @Html.ValidationMessage("EncryptionMethod", "*") + @T("The encryption method used when connecting to mail server.") +
        +
        + @Html.EditorFor(m => m.AutoSelectEncryption) + + @Html.ValidationMessage("AutoSelectEncryption", "*") + @T("Check to let the system select the encryption method based on port.")
        @Html.EditorFor(m => m.RequireCredentials) @Html.ValidationMessage("RequireCredentials", "*")
        -
        -
        - @Html.RadioButtonFor(m => m.UseDefaultCredentials, false, new { id = "customCredentialsOption", name = "UseDefaultCredentials" }) - - @Html.ValidationMessage("UseDefaultCredentials", "*") + + @Html.TextBoxFor(m => m.UserName, new { @class = "text medium" }) + @Html.ValidationMessage("UserName", "*") + @T("The username for authentication.")
        -
        - @Html.RadioButtonFor(m => m.UseDefaultCredentials, true, new { id = "defaultCredentialsOptions", name = "UseDefaultCredentials" }) - - @Html.ValidationMessage("UseDefaultCredentials", "*") - @T("When this option is selected, the aplication pool or host-process identity is used to authenticate with the mail server. ") -
        -
        - - - @Html.TextBoxFor(m => m.UserName, new { @class = "text" }) - @Html.ValidationMessage("UserName", "*") - @T("The username for authentication.") - - - - @Html.TextBoxFor(m => m.Password, new { type = "password", @class = "text medium" }) - @Html.ValidationMessage("Password", "*") - @T("The password for authentication.") - + + @Html.TextBoxFor(m => m.Password, new { type = "password", @class = "text medium" }) + @Html.ValidationMessage("Password", "*") + @T("The password for authentication.")
        +
        + + @Html.TextBoxFor(m => m.ListUnsubscribe, new { @class = "text medium" }) + @T("A mailto:link to unsubscribe a user when clicking unsubscribe option") +
        @T("Test those settings:") @@ -84,26 +105,32 @@ var url = "@Url.Action("TestSettings", "EmailAdmin", new {area = "Orchard.Email"})", error = $("#emailtesterror"), info = $("#emailtestinfo"), - from = $("#@Html.FieldIdFor(m => m.Address)"), + fromAddress = $("#@Html.FieldIdFor(m => m.FromAddress)"), + fromName = $("#@Html.FieldIdFor(m => m.FromName)"), + replyTo = $("#@Html.FieldIdFor(m => m.ReplyTo)"), host = $("#@Html.FieldIdFor(m => m.Host)"), port = $("#@Html.FieldIdFor(m => m.Port)"), - enableSsl = $("#@Html.FieldIdFor(m => m.EnableSsl)"), + encryptionMethod = $("#@Html.FieldIdFor(m => m.EncryptionMethod)"), + autoSelectEncryption = $("#@Html.FieldIdFor(m => m.AutoSelectEncryption)"), requireCredentials = $("#@Html.FieldIdFor(m => m.RequireCredentials)"), - useDefaultCredentials = $("input[name='@Html.NameFor(m => m.UseDefaultCredentials)']"), userName = $("#@Html.FieldIdFor(m => m.UserName)"), password = $("#@Html.FieldIdFor(m => m.Password)"), + listUnsubscribe = $("#@Html.FieldIdFor(m => m.ListUnsubscribe)"), to = $("#emailtestto"); $("#emailtestsend").click(function () { $.post(url, { - from: from.val(), + fromAddress: fromAddress.val(), + fromName: fromName.val(), + replyTo: replyTo.val(), host: host.val(), port: port.val(), - enableSsl: enableSsl.prop("checked"), + encryptionMethod: encryptionMethod.val(), + autoSelectEncryption: autoSelectEncryption.prop("checked"), requireCredentials: requireCredentials.prop("checked"), - useDefaultCredentials: useDefaultCredentials.filter(':checked').val(), userName: userName.val(), password: password.val(), + listUnsubscribe: listUnsubscribe.val(), to: to.val(), __RequestVerificationToken: to.closest("form").find("input[name=__RequestVerificationToken]").val() }) diff --git a/src/Orchard.Web/Modules/Orchard.Email/Web.config b/src/Orchard.Web/Modules/Orchard.Email/Web.config index a3cb5df907e..fd7fac8e5c2 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Email/Web.config @@ -7,7 +7,7 @@ - + @@ -21,39 +21,59 @@ + + + - + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Email/packages.config b/src/Orchard.Web/Modules/Orchard.Email/packages.config index 1ea27eef99b..36c1ec1d6da 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Email/packages.config @@ -1,8 +1,13 @@  - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/BooleanFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/BooleanFieldDriver.cs index b126ceef464..6d07a6ad045 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/BooleanFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/BooleanFieldDriver.cs @@ -62,8 +62,7 @@ protected override void Importing(ContentPart part, BooleanField field, ImportCo } protected override void Exporting(ContentPart part, BooleanField field, ExportContentContext context) { - if (field.Value.HasValue) - context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Value", field.Value); + context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Value", field.Value); } protected override void Cloning(ContentPart part, BooleanField originalField, BooleanField cloneField, CloneContentContext context) { @@ -72,7 +71,7 @@ protected override void Cloning(ContentPart part, BooleanField originalField, Bo protected override void Describe(DescribeMembersContext context) { context - .Member(null, typeof(Boolean), T("Value"), T("The boolean value of the field.")) + .Member(null, typeof(Boolean?), T("Value"), T("The boolean value of the field.")) .Enumerate(() => field => new [] { field.Value }) ; } diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/DateTimeFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/DateTimeFieldDriver.cs index 039bc6f0739..e5fafddbb86 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/DateTimeFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/DateTimeFieldDriver.cs @@ -13,8 +13,6 @@ namespace Orchard.Fields.Drivers { public class DateTimeFieldDriver : ContentFieldDriver { - private const string TemplateName = "Fields/DateTime.Edit"; // EditorTemplates/Fields/DateTime.Edit.cshtml - public DateTimeFieldDriver(IOrchardServices services, IDateLocalizationServices dateLocalizationServices) { Services = services; DateLocalizationServices = dateLocalizationServices; @@ -34,50 +32,48 @@ private static string GetDifferentiator(ContentField field, ContentPart part) { } protected override DriverResult Display(ContentPart part, DateTimeField field, string displayType, dynamic shapeHelper) { - return ContentShape("Fields_DateTime", // this is just a key in the Shape Table - GetDifferentiator(field, part), - () => { - var settings = field.PartFieldDefinition.Settings.GetModel(); - var value = field.DateTime; - var options = new DateLocalizationOptions(); - - // Don't do any time zone conversion if field is semantically a date-only field, because that might mutate the date component. - if (settings.Display == DateTimeFieldDisplays.DateOnly) { - options.EnableTimeZoneConversion = false; - } + return ContentShape("Fields_DateTime", GetDifferentiator(field, part), () => { + var settings = field.PartFieldDefinition.Settings.GetModel(); + var value = field.DateTime; + var options = new DateLocalizationOptions(); - // Don't do any calendar conversion if field is semantically a time-only field, because the date component might we out of allowed boundaries for the current calendar. - if (settings.Display == DateTimeFieldDisplays.TimeOnly) { - options.EnableCalendarConversion = false; - options.IgnoreDate = true; - } + // Don't do any time zone conversion if field is semantically a date-only field, because that might mutate the date component. + if (settings.Display == DateTimeFieldDisplays.DateOnly) { + options.EnableTimeZoneConversion = false; + } - var showDate = settings.Display == DateTimeFieldDisplays.DateAndTime || settings.Display == DateTimeFieldDisplays.DateOnly; - var showTime = settings.Display == DateTimeFieldDisplays.DateAndTime || settings.Display == DateTimeFieldDisplays.TimeOnly; - - var viewModel = new DateTimeFieldViewModel { - Name = field.DisplayName, - Hint = settings.Hint, - IsRequired = settings.Required, - Editor = new DateTimeEditor() { - Date = showDate ? DateLocalizationServices.ConvertToLocalizedDateString(value, options) : null, - Time = showTime ? DateLocalizationServices.ConvertToLocalizedTimeString(value, options) : null, - ShowDate = showDate, - ShowTime = showTime, - DatePlaceholder = settings.DatePlaceholder, - TimePlaceholder = settings.TimePlaceholder - } - }; - - return shapeHelper.Fields_DateTime( // this is the actual Shape which will be resolved (Fields/DateTime.cshtml) - Model: viewModel); + // Don't do any calendar conversion if field is semantically a time-only field, because the date component might we out of allowed boundaries for the current calendar. + if (settings.Display == DateTimeFieldDisplays.TimeOnly) { + options.EnableCalendarConversion = false; + options.IgnoreDate = true; } - ); + + var showDate = settings.Display == DateTimeFieldDisplays.DateAndTime || settings.Display == DateTimeFieldDisplays.DateOnly; + var showTime = settings.Display == DateTimeFieldDisplays.DateAndTime || settings.Display == DateTimeFieldDisplays.TimeOnly; + + var viewModel = new DateTimeFieldViewModel { + Name = field.DisplayName, + Hint = settings.Hint, + Value = value, + IsRequired = settings.Required, + Editor = new DateTimeEditor() { + Date = showDate ? DateLocalizationServices.ConvertToLocalizedDateString(value, options) : null, + Time = showTime ? DateLocalizationServices.ConvertToLocalizedTimeString(value, options) : null, + ShowDate = showDate, + ShowTime = showTime, + DatePlaceholder = settings.DatePlaceholder, + TimePlaceholder = settings.TimePlaceholder + } + }; + + // this is the actual Shape which will be resolved (Fields/DateTime.cshtml) + return shapeHelper.Fields_DateTime(Model: viewModel); + }); } protected override DriverResult Editor(ContentPart part, DateTimeField field, dynamic shapeHelper) { var settings = field.PartFieldDefinition.Settings.GetModel(); - var value = part.IsNew() && field.DateTime == default(DateTime) ? settings.DefaultValue : field.DateTime; + var value = part.IsNew() && field.DateTime == null ? settings.DefaultValue : field.DateTime; var options = new DateLocalizationOptions(); // Don't do any time zone conversion if field is semantically a date-only field, because that might mutate the date component. @@ -97,6 +93,7 @@ protected override DriverResult Editor(ContentPart part, DateTimeField field, dy var viewModel = new DateTimeFieldViewModel { Name = field.DisplayName, Hint = settings.Hint, + Value = value, IsRequired = settings.Required, Editor = new DateTimeEditor() { Date = showDate ? DateLocalizationServices.ConvertToLocalizedDateString(value, options) : null, @@ -109,16 +106,14 @@ protected override DriverResult Editor(ContentPart part, DateTimeField field, dy }; return ContentShape("Fields_DateTime_Edit", GetDifferentiator(field, part), - () => shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: viewModel, Prefix: GetPrefix(field, part))); + () => shapeHelper.EditorTemplate(TemplateName: "Fields/DateTime.Edit", Model: viewModel, Prefix: GetPrefix(field, part))); } protected override DriverResult Editor(ContentPart part, DateTimeField field, IUpdateModel updater, dynamic shapeHelper) { var viewModel = new DateTimeFieldViewModel(); if (updater.TryUpdateModel(viewModel, GetPrefix(field, part), null, null)) { - var settings = field.PartFieldDefinition.Settings.GetModel(); - var options = new DateLocalizationOptions(); // Don't do any time zone conversion if field is semantically a date-only field, because that might mutate the date component. @@ -138,7 +133,7 @@ protected override DriverResult Editor(ContentPart part, DateTimeField field, IU DateTime? value = null; // Try to parse data if not required or if there are no missing fields. - if (!settings.Required || ((!showDate || !String.IsNullOrWhiteSpace(viewModel.Editor.Date)) && (!showTime || !String.IsNullOrWhiteSpace(viewModel.Editor.Time)))) { + if (!settings.Required || ((!showDate || !string.IsNullOrWhiteSpace(viewModel.Editor.Date)) && (!showTime || !string.IsNullOrWhiteSpace(viewModel.Editor.Time)))) { try { value = DateLocalizationServices.ConvertFromLocalizedString(viewModel.Editor.Date, viewModel.Editor.Time, options); } @@ -158,20 +153,20 @@ protected override DriverResult Editor(ContentPart part, DateTimeField field, IU updater.AddModelError(GetPrefix(field, part), T("{0} is required.", T(field.DisplayName))); } - field.DateTime = value.HasValue ? value.Value : DateTime.MinValue; + field.DateTime = value; } return Editor(part, field, shapeHelper); } protected override void Importing(ContentPart part, DateTimeField field, ImportContentContext context) { - context.ImportAttribute(GetPrefix(field, part), "Value", v => field.Storage.Set(null, XmlConvert.ToDateTime(v, XmlDateTimeSerializationMode.Utc))); + context.ImportAttribute(field.FieldDefinition.Name + "." + field.Name, "Value", v => + field.DateTime = string.IsNullOrEmpty(v) ? null : (DateTime?)XmlConvert.ToDateTime(v, XmlDateTimeSerializationMode.Utc)); } protected override void Exporting(ContentPart part, DateTimeField field, ExportContentContext context) { - var value = field.Storage.Get(null); - if (value != DateTime.MinValue) - context.Element(GetPrefix(field, part)).SetAttributeValue("Value", XmlConvert.ToString(value, XmlDateTimeSerializationMode.Utc)); + context.Element(field.FieldDefinition.Name + "." + field.Name) + .SetAttributeValue("Value", field.DateTime.HasValue ? XmlConvert.ToString(field.DateTime.Value, XmlDateTimeSerializationMode.Utc) : ""); } protected override void Cloning(ContentPart part, DateTimeField originalField, DateTimeField cloneField, CloneContentContext context) { diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/EnumerationFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/EnumerationFieldDriver.cs index ed92d98dfc7..3240df55d17 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/EnumerationFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/EnumerationFieldDriver.cs @@ -4,46 +4,41 @@ using Orchard.Fields.Fields; using Orchard.Fields.Settings; using Orchard.Localization; -using System; -using System.Collections.Generic; -using System.Linq; namespace Orchard.Fields.Drivers { public class EnumerationFieldDriver : ContentFieldDriver { public IOrchardServices Services { get; set; } + private const string TemplateName = "Fields/Enumeration.Edit"; public EnumerationFieldDriver(IOrchardServices services) { Services = services; + T = NullLocalizer.Instance; } public Localizer T { get; set; } - private static string GetPrefix(ContentField field, ContentPart part) { - return part.PartDefinition.Name + "." + field.Name; - } + private static string GetPrefix(ContentField field, ContentPart part) => + part.PartDefinition.Name + "." + field.Name; - private static string GetDifferentiator(EnumerationField field, ContentPart part) { - return field.Name; - } + private static string GetDifferentiator(EnumerationField field) => field.Name; protected override DriverResult Display(ContentPart part, EnumerationField field, string displayType, dynamic shapeHelper) { - return ContentShape("Fields_Enumeration", GetDifferentiator(field, part), - () => shapeHelper.Fields_Enumeration()); + return ContentShape("Fields_Enumeration", GetDifferentiator(field), () => shapeHelper.Fields_Enumeration()); } protected override DriverResult Editor(ContentPart part, EnumerationField field, dynamic shapeHelper) { - return ContentShape("Fields_Enumeration_Edit", GetDifferentiator(field, part), - () => { - if (part.IsNew() && String.IsNullOrEmpty(field.Value)) { - var settings = field.PartFieldDefinition.Settings.GetModel(); - if (!String.IsNullOrWhiteSpace(settings.DefaultValue)) { - field.Value = settings.DefaultValue; - } + return ContentShape("Fields_Enumeration_Edit", GetDifferentiator(field), () => { + if (part.IsNew() && string.IsNullOrEmpty(field.Value)) { + var settings = field.PartFieldDefinition.Settings.GetModel(); + if (!string.IsNullOrWhiteSpace(settings.DefaultValue)) { + field.SelectedValues = new string[] { settings.DefaultValue }; } - return shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: field, Prefix: GetPrefix(field, part)); - }); + } + + return shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: field, Prefix: GetPrefix(field, part)); + }); } protected override DriverResult Editor(ContentPart part, EnumerationField field, IUpdateModel updater, dynamic shapeHelper) { @@ -63,8 +58,7 @@ protected override void Importing(ContentPart part, EnumerationField field, Impo } protected override void Exporting(ContentPart part, EnumerationField field, ExportContentContext context) { - if (!String.IsNullOrEmpty(field.Value)) - context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Value", field.Value); + context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Value", field.Value); } protected override void Cloning(ContentPart part, EnumerationField originalField, EnumerationField cloneField, CloneContentContext context) { diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/InputFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/InputFieldDriver.cs index 625dba93a23..8539daf6369 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/InputFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/InputFieldDriver.cs @@ -61,8 +61,7 @@ protected override void Importing(ContentPart part, InputField field, ImportCont } protected override void Exporting(ContentPart part, InputField field, ExportContentContext context) { - if (!String.IsNullOrEmpty(field.Value)) - context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Value", field.Value); + context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Value", field.Value); } protected override void Cloning(ContentPart part, InputField originalField, InputField cloneField, CloneContentContext context) { diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/LinkFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/LinkFieldDriver.cs index 7298be8b892..2119023a6df 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/LinkFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/LinkFieldDriver.cs @@ -75,11 +75,9 @@ protected override void Importing(ContentPart part, LinkField field, ImportConte } protected override void Exporting(ContentPart part, LinkField field, ExportContentContext context) { - if (!String.IsNullOrEmpty(field.Text) || !String.IsNullOrEmpty(field.Value) || !String.IsNullOrEmpty(field.Target)) { - context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Text", field.Text); - context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Url", field.Value); - context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Target", field.Target); - } + context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Text", field.Text); + context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Url", field.Value); + context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Target", field.Target); } protected override void Cloning(ContentPart part, LinkField originalField, LinkField cloneField, CloneContentContext context) { diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/NumericFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/NumericFieldDriver.cs index a8794abaf6e..d7394be5412 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/NumericFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/NumericFieldDriver.cs @@ -102,12 +102,17 @@ protected override DriverResult Editor(ContentPart part, NumericField field, IUp } protected override void Importing(ContentPart part, NumericField field, ImportContentContext context) { - context.ImportAttribute(field.FieldDefinition.Name + "." + field.Name, "Value", v => field.Value = decimal.Parse(v, CultureInfo.InvariantCulture), () => field.Value = (decimal?)null); + Action empty = (() => field.Value = (decimal?)null); + var element = context.Data.Element(field.FieldDefinition.Name + "." + field.Name); + // If element is not in the ImportContentContext, field must not be reset. + if (element == null) { + empty = () => { }; + } + context.ImportAttribute(field.FieldDefinition.Name + "." + field.Name, "Value", v => field.Value = decimal.Parse(v, CultureInfo.InvariantCulture), empty); } protected override void Exporting(ContentPart part, NumericField field, ExportContentContext context) { - if (field.Value.HasValue) - context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Value", field.Value.Value.ToString(CultureInfo.InvariantCulture)); + context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Value", !field.Value.HasValue ? String.Empty : field.Value.Value.ToString(CultureInfo.InvariantCulture)); } protected override void Cloning(ContentPart part, NumericField originalField, NumericField cloneField, CloneContentContext context) { diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Fields/DateTimeField.cs b/src/Orchard.Web/Modules/Orchard.Fields/Fields/DateTimeField.cs index c8692250451..bc1c4fb0a7b 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Fields/DateTimeField.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Fields/DateTimeField.cs @@ -6,32 +6,32 @@ namespace Orchard.Fields.Fields { public class DateTimeField : ContentField { - public DateTime DateTime { + public DateTime? DateTime { get { - var settings = this.PartFieldDefinition.Settings.GetModel(); - var value = Storage.Get(); - if (settings.Display == DateTimeFieldDisplays.DateOnly) { - return new DateTime(value.Year, value.Month, value.Day); - } - return value; + var settings = PartFieldDefinition.Settings.GetModel(); + var value = Storage.Get(); + + return value.HasValue && settings.Display == DateTimeFieldDisplays.DateOnly ? + new DateTime(value.Value.Year, value.Value.Month, value.Value.Day) : value; } set { - var settings = this.PartFieldDefinition.Settings.GetModel(); - if (settings.Display == DateTimeFieldDisplays.DateOnly) { - Storage.Set(new DateTime(value.Year, value.Month, value.Day)); + if (value.HasValue) { + var settings = PartFieldDefinition.Settings.GetModel(); + + Storage.Set(settings.Display == DateTimeFieldDisplays.DateOnly ? + new DateTime(value.Value.Year, value.Value.Month, value.Value.Day) : value.Value); } else { - Storage.Set(value); + Storage.Set(null); } } } public DateTimeFieldDisplays Display { get { - var settings = this.PartFieldDefinition.Settings.GetModel(); - return settings.Display; + return PartFieldDefinition.Settings.GetModel().Display; } } - } + } } diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Fields/EnumerationField.cs b/src/Orchard.Web/Modules/Orchard.Fields/Fields/EnumerationField.cs index a81d6829e0a..ee572b66bd4 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Fields/EnumerationField.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Fields/EnumerationField.cs @@ -7,28 +7,16 @@ public class EnumerationField : ContentField { private const char Separator = ';'; public string Value { - get { return Storage.Get(); } - set { Storage.Set(value ?? String.Empty); } + get => Storage.Get()?.Trim(Separator) ?? ""; + set => Storage.Set(string.IsNullOrWhiteSpace(value) + ? string.Empty + // It is now the responsibility of this field to (re-)add the separators. + : Separator + value.Trim(Separator) + Separator); } public string[] SelectedValues { - get { - var value = Value; - if(string.IsNullOrWhiteSpace(value)) { - return new string[0]; - } - - return value.Split(new [] { Separator }, StringSplitOptions.RemoveEmptyEntries); - } - - set { - if (value == null || value.Length == 0) { - Value = String.Empty; - } - else { - Value = Separator + string.Join(Separator.ToString(), value) + Separator; - } - } + get => Value?.Split(new[] { Separator }, StringSplitOptions.RemoveEmptyEntries) ?? new string[0]; + set => Value = value?.Length > 0 ? string.Join(Separator.ToString(), value) : ""; } } } diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Module.txt b/src/Orchard.Web/Modules/Orchard.Fields/Module.txt index 2099ea0db3c..82172333538 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Fields/Module.txt @@ -2,8 +2,8 @@ Name: Fields AntiForgery: enabled Author: Antoine Griffard, Sbastien Ros Website: http://www.orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Some content fields Features: Orchard.Fields: diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Orchard.Fields.csproj b/src/Orchard.Web/Modules/Orchard.Fields/Orchard.Fields.csproj index 354f9e1c8ab..d4c296342be 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Orchard.Fields.csproj +++ b/src/Orchard.Web/Modules/Orchard.Fields/Orchard.Fields.csproj @@ -12,8 +12,8 @@ Properties Orchard.Fields Orchard.Fields - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,9 @@ + + + true @@ -49,10 +52,12 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -67,29 +72,23 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -107,12 +106,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {6f759635-13d7-4e94-bcc9-80445d63f117} @@ -175,7 +174,7 @@ - + 10.0 @@ -201,7 +200,7 @@ --> - + @@ -215,10 +214,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Fields/Properties/AssemblyInfo.cs index 1bea5f40b24..52b49c92acb 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Settings/DateTimeFieldEditorEvents.cs b/src/Orchard.Web/Modules/Orchard.Fields/Settings/DateTimeFieldEditorEvents.cs index 50a5be156d9..9acb1d22aef 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Settings/DateTimeFieldEditorEvents.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Settings/DateTimeFieldEditorEvents.cs @@ -20,12 +20,7 @@ public DateTimeFieldEditorEvents(IDateLocalizationServices dateLocalizationServi public override IEnumerable PartFieldEditor(ContentPartFieldDefinition definition) { if (definition.FieldDefinition.Name == "DateTimeField") { var model = definition.Settings.GetModel(); - model.Editor = new DateTimeEditor() { - ShowDate = true, - ShowTime = true, - Date = _dateLocalizationServices.ConvertToLocalizedDateString(model.DefaultValue), - Time = _dateLocalizationServices.ConvertToLocalizedTimeString(model.DefaultValue), - }; + model.Editor = InitialDateTimeEditor(model.DefaultValue); yield return DefinitionTemplate(model); } } @@ -44,9 +39,23 @@ public override IEnumerable PartFieldEditorUpdate(ContentPart builder.WithSetting("DateTimeFieldSettings.TimePlaceholder", model.TimePlaceholder); model.DefaultValue = model.Editor == null ? model.DefaultValue : _dateLocalizationServices.ConvertFromLocalizedString(model.Editor.Date, model.Editor.Time); builder.WithSetting("DateTimeFieldSettings.DefaultValue", model.DefaultValue.HasValue ? model.DefaultValue.Value.ToString(CultureInfo.InvariantCulture) : String.Empty); - + model.Editor = InitialDateTimeEditor(model.DefaultValue, model.Display); yield return DefinitionTemplate(model); } } + + private DateTimeEditor InitialDateTimeEditor(DateTime? value, DateTimeFieldDisplays displays = DateTimeFieldDisplays.DateAndTime) + { + var showDate = displays == DateTimeFieldDisplays.DateAndTime || displays == DateTimeFieldDisplays.DateOnly; + var showTime = displays == DateTimeFieldDisplays.DateAndTime || displays == DateTimeFieldDisplays.TimeOnly; + var editor = new DateTimeEditor() + { + ShowDate = showDate, + ShowTime = showTime, + Date = value != null ? _dateLocalizationServices.ConvertToLocalizedDateString(value) : null, + Time = value != null ? _dateLocalizationServices.ConvertToLocalizedTimeString(value) : null + }; + return editor; + } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Tokens/FieldTokens.cs b/src/Orchard.Web/Modules/Orchard.Fields/Tokens/FieldTokens.cs index 25ef969bfcc..7dec352bfc2 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Tokens/FieldTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Tokens/FieldTokens.cs @@ -55,9 +55,9 @@ public void Evaluate(dynamic context) { ; context.For("DateTimeField") - .Token("Date", (Func)(d => d.DateTime.ToString(_dateTimeLocalization.ShortDateFormat, _cultureInfo.Value))) - .Token("Time", (Func)(d => d.DateTime.ToString(_dateTimeLocalization.ShortTimeFormat, _cultureInfo.Value))) - .Token("DateTime", (Func)(d => d.DateTime.ToString(_dateTimeLocalization.ShortDateTimeFormat, _cultureInfo.Value))) + .Token("Date", (Func)(d => d.DateTime.HasValue ? d.DateTime.Value.ToString(_dateTimeLocalization.ShortDateFormat, _cultureInfo.Value) : null)) + .Token("Time", (Func)(d => d.DateTime.HasValue ? d.DateTime.Value.ToString(_dateTimeLocalization.ShortTimeFormat, _cultureInfo.Value) : null)) + .Token("DateTime", (Func)(d => d.DateTime.HasValue ? d.DateTime.Value.ToString(_dateTimeLocalization.ShortDateTimeFormat, _cultureInfo.Value) : null)) .Chain("DateTime", "Date", (Func)(field => field.DateTime)) ; } diff --git a/src/Orchard.Web/Modules/Orchard.Fields/ViewModels/DateTimeFieldViewModel.cs b/src/Orchard.Web/Modules/Orchard.Fields/ViewModels/DateTimeFieldViewModel.cs index d140dcbd0a4..a4a6f67bd71 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/ViewModels/DateTimeFieldViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/ViewModels/DateTimeFieldViewModel.cs @@ -1,9 +1,11 @@ -using Orchard.Core.Common.ViewModels; +using System; +using Orchard.Core.Common.ViewModels; namespace Orchard.Fields.ViewModels { public class DateTimeFieldViewModel { public string Name { get; set; } public string Hint { get; set; } + public DateTime? Value { get; set; } public bool IsRequired { get; set; } public DateTimeEditor Editor { get; set; } } diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Views/DefinitionTemplates/NumericFieldSettings.cshtml b/src/Orchard.Web/Modules/Orchard.Fields/Views/DefinitionTemplates/NumericFieldSettings.cshtml index 632c650521c..1dcd35d345a 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Views/DefinitionTemplates/NumericFieldSettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Fields/Views/DefinitionTemplates/NumericFieldSettings.cshtml @@ -1,5 +1,4 @@ @model Orchard.Fields.Settings.NumericFieldSettings -@using Orchard.Fields.Settings;
        @@ -50,6 +49,8 @@
        + @Html.TextBoxFor(m => m.DefaultValue, new { @class = "text large tokenized ui-autocomplete-input" }) + @T("The default value for the field. It must be a number, and if not it will not be shown. Make sure to set the Scale property if the value is not an integer. You can use tokens in this field. (optional)") @Html.ValidationMessageFor(m => m.DefaultValue)
        diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/Boolean.Edit.cshtml b/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/Boolean.Edit.cshtml index c039f3e8195..f0b1188b9eb 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/Boolean.Edit.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/Boolean.Edit.cshtml @@ -1,5 +1,4 @@ @model Orchard.Fields.Fields.BooleanField -@using Orchard.Utility.Extensions; @using Orchard.Fields.Settings; @{ var settings = Model.PartFieldDefinition.Settings.GetModel(); @@ -9,22 +8,22 @@ @switch (settings.SelectionMode) { case SelectionMode.Checkbox: checked="checked" } /> - + break; case SelectionMode.Radiobutton: if (settings.Optional) {
        - checked="checked" } /> - + checked="checked" } /> +
        }
        - checked="checked" } /> - + checked="checked" } /> +
        - checked="checked" } /> - + checked="checked" } /> +
        break; case SelectionMode.Dropdown: diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/Enumeration.Edit.cshtml b/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/Enumeration.Edit.cshtml index 1e2b077749b..0f3d1003600 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/Enumeration.Edit.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Fields/Views/EditorTemplates/Fields/Enumeration.Edit.cshtml @@ -1,22 +1,27 @@ @model Orchard.Fields.Fields.EnumerationField + @using Orchard.Fields.Settings; + @{ var settings = Model.PartFieldDefinition.Settings.GetModel(); string[] options = (!String.IsNullOrWhiteSpace(settings.Options)) ? settings.Options.Split(new string[] { System.Environment.NewLine }, StringSplitOptions.None) : new string[] { T("Select an option").ToString() }; } +
        - + @switch (settings.ListMode) { case ListMode.Dropdown: - @Html.DropDownListFor(m => m.Value, new SelectList(options, Model.Value), settings.Required ? new { required = "required" } : null) + @Html.DropDownListFor(m => m.Value, new SelectList(options, Model.SelectedValues.FirstOrDefault()), settings.Required ? new { required = "required" } : null) break; case ListMode.Radiobutton: foreach (var option in options) { if (string.IsNullOrWhiteSpace(option)) { - } + + } else { - } + + } } break; @@ -33,7 +38,7 @@ if (!string.IsNullOrWhiteSpace(option)) {
        - +
        } } diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/DateTime.cshtml b/src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/DateTime.cshtml index 45e0ccf0b5b..813f1a83647 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/DateTime.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/DateTime.cshtml @@ -1,9 +1,16 @@ @using Orchard.Utility.Extensions; @{ + var viewModel = Model.Model as DateTimeFieldViewModel; + + if (!viewModel.Value.HasValue) + { + return; + } + string name = Model.ContentField.DisplayName; }

        @name.CamelFriendly(): - @if (Model.Model.Editor.ShowDate) {@Model.Model.Editor.Date} @if (Model.Model.Editor.ShowTime) {@Model.Model.Editor.Time} + @if (viewModel.Editor.ShowDate) {@viewModel.Editor.Date} @if (viewModel.Editor.ShowTime) {@viewModel.Editor.Time}

        diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/Input.cshtml b/src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/Input.cshtml index cf594c57436..a06c967c4e1 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/Input.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Fields/Views/Fields/Input.cshtml @@ -1,9 +1,7 @@ -@using Orchard.Fields.Settings; -@using Orchard.Utility.Extensions; -@{ +@{ string value = (string)Model.ContentField.Value; if (!string.IsNullOrEmpty(value)) { string name = Model.ContentField.DisplayName; -

        @T(name): @value

        +

        @T.Encode(name): @value

        } } diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Web.config b/src/Orchard.Web/Modules/Orchard.Fields/Web.config index ab41a6ad309..541deb171a2 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Fields/Web.config @@ -7,7 +7,7 @@ - + @@ -22,38 +22,57 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Fields/packages.config b/src/Orchard.Web/Modules/Orchard.Fields/packages.config index 6729ced4977..1c55d6960bb 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Fields/packages.config @@ -1,7 +1,8 @@  - - - - - \ No newline at end of file + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Forms/Module.txt b/src/Orchard.Web/Modules/Orchard.Forms/Module.txt index 83ed4be32e9..bf1b237b5c1 100644 --- a/src/Orchard.Web/Modules/Orchard.Forms/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Forms/Module.txt @@ -2,8 +2,8 @@ Name: Forms AntiForgery: enabled Author: The Orchard Team Website: http://www.orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Provides a system to publish and alter html forms. Features: Orchard.Forms: diff --git a/src/Orchard.Web/Modules/Orchard.Forms/Orchard.Forms.csproj b/src/Orchard.Web/Modules/Orchard.Forms/Orchard.Forms.csproj index 8740abe40c8..e4fa58018d2 100644 --- a/src/Orchard.Web/Modules/Orchard.Forms/Orchard.Forms.csproj +++ b/src/Orchard.Web/Modules/Orchard.Forms/Orchard.Forms.csproj @@ -12,8 +12,8 @@ Properties Orchard.Forms Orchard.Forms - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,7 @@ + true @@ -52,11 +53,9 @@ ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - - ..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True + + ..\..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll @@ -72,29 +71,23 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -111,12 +104,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) @@ -131,7 +124,10 @@ - + + + + 10.0 @@ -157,7 +153,7 @@ --> - + @@ -171,10 +167,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Forms/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Forms/Properties/AssemblyInfo.cs index 80ed8c3a1d8..2ddef3b038e 100644 --- a/src/Orchard.Web/Modules/Orchard.Forms/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Forms/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Forms/Shapes/EditorShapes.cs b/src/Orchard.Web/Modules/Orchard.Forms/Shapes/EditorShapes.cs index 0a494543a7a..5228fd45524 100644 --- a/src/Orchard.Web/Modules/Orchard.Forms/Shapes/EditorShapes.cs +++ b/src/Orchard.Web/Modules/Orchard.Forms/Shapes/EditorShapes.cs @@ -224,6 +224,12 @@ public IHtmlString Textbox(dynamic Display, dynamic Shape) { return DisplayShapeAsInput(Display, Shape, "text"); } + [Shape] + public IHtmlString Numberbox(dynamic Display, dynamic Shape) { + Shape.Classes.Add("number"); + return DisplayShapeAsInput(Display, Shape, "number"); + } + [Shape] public IHtmlString Password(dynamic Display, dynamic Shape) { Shape.Classes.Add("password"); @@ -235,24 +241,24 @@ public void Textarea( TextWriter Output, dynamic Display, dynamic Shape, string Name, string Value, int Size = 0, int Rows = 0) { - var select = (TagBuilder)_tagBuilderFactory.Create(Shape, "textarea"); - select.AddCssClass("text"); + var textarea = (TagBuilder)_tagBuilderFactory.Create(Shape, "textarea"); + textarea.AddCssClass("text"); if (Name != null) { - select.MergeAttribute("name", Name, false); + textarea.MergeAttribute("name", Name, false); } if (Size > 0) { - select.MergeAttribute("size", Size.ToString(), false); + textarea.MergeAttribute("size", Size.ToString(), false); } if (Rows > 0) { - select.MergeAttribute("rows", Rows.ToString(), false); + textarea.MergeAttribute("rows", Rows.ToString(), false); } - Output.Write(select.ToString(TagRenderMode.StartTag)); + Output.Write(textarea.ToString(TagRenderMode.StartTag)); Output.Write(Value); - Output.WriteLine(select.ToString(TagRenderMode.EndTag)); + Output.WriteLine(textarea.ToString(TagRenderMode.EndTag)); } [Shape] diff --git a/src/Orchard.Web/Modules/Orchard.Forms/Web.config b/src/Orchard.Web/Modules/Orchard.Forms/Web.config index a3cb5df907e..73a184e136a 100644 --- a/src/Orchard.Web/Modules/Orchard.Forms/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Forms/Web.config @@ -7,7 +7,7 @@ - + @@ -22,38 +22,49 @@ - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Forms/packages.config b/src/Orchard.Web/Modules/Orchard.Forms/packages.config index 1ea27eef99b..f89bcaa42ad 100644 --- a/src/Orchard.Web/Modules/Orchard.Forms/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Forms/packages.config @@ -1,8 +1,8 @@  - - - - - - \ No newline at end of file + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Glimpse/ADO/GlimpseDriver.cs b/src/Orchard.Web/Modules/Orchard.Glimpse/ADO/GlimpseDriver.cs index f7c4a74fb7f..0c4caaf3f6b 100644 --- a/src/Orchard.Web/Modules/Orchard.Glimpse/ADO/GlimpseDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Glimpse/ADO/GlimpseDriver.cs @@ -20,40 +20,52 @@ public void Configure(IDictionary settings) { _decoratedService.Configure(settings); } - public IDbConnection CreateConnection() { + public DbConnection CreateConnection() { return new GlimpseDbConnection(_decoratedService.CreateConnection() as DbConnection); } - public IDbCommand GenerateCommand(CommandType type, SqlString sqlString, SqlType[] parameterTypes) { + public DbCommand GenerateCommand(CommandType type, SqlString sqlString, SqlType[] parameterTypes) { return new GlimpseDbCommand(_decoratedService.GenerateCommand(type, sqlString, parameterTypes) as DbCommand); } - public void PrepareCommand(IDbCommand command) { + public void PrepareCommand(DbCommand command) { _decoratedService.PrepareCommand(command); } - public IDbDataParameter GenerateParameter(IDbCommand command, string name, SqlType sqlType) { + public DbParameter GenerateParameter(DbCommand command, string name, SqlType sqlType) { return _decoratedService.GenerateParameter(command, name, sqlType); } - public void RemoveUnusedCommandParameters(IDbCommand cmd, SqlString sqlString) { + public void RemoveUnusedCommandParameters(DbCommand cmd, SqlString sqlString) { _decoratedService.RemoveUnusedCommandParameters(cmd, sqlString); } - public void ExpandQueryParameters(IDbCommand cmd, SqlString sqlString) { - _decoratedService.ExpandQueryParameters(cmd, sqlString); + public void ExpandQueryParameters(DbCommand cmd, SqlString sqlString, SqlType[] parameterTypes) { + _decoratedService.ExpandQueryParameters(cmd, sqlString, parameterTypes); } public IResultSetsCommand GetResultSetsCommand(ISessionImplementor session) { return _decoratedService.GetResultSetsCommand(session); } - public void AdjustCommand(IDbCommand command) { + public void AdjustCommand(DbCommand command) { _decoratedService.AdjustCommand(command); } public bool SupportsMultipleOpenReaders => _decoratedService.SupportsMultipleOpenReaders; public bool SupportsMultipleQueries => _decoratedService.SupportsMultipleQueries; + + public bool RequiresTimeSpanForTime => _decoratedService.RequiresTimeSpanForTime; + + public bool SupportsSystemTransactions => _decoratedService.SupportsSystemTransactions; + + public bool SupportsNullEnlistment => _decoratedService.SupportsNullEnlistment; + + public bool SupportsEnlistmentWhenAutoEnlistmentIsDisabled => _decoratedService.SupportsEnlistmentWhenAutoEnlistmentIsDisabled; + + public bool HasDelayedDistributedTransactionCompletion => _decoratedService.HasDelayedDistributedTransactionCompletion; + + public DateTime MinDate => _decoratedService.MinDate; } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Glimpse/GlimpseSecurityPolicy.cs b/src/Orchard.Web/Modules/Orchard.Glimpse/GlimpseSecurityPolicy.cs new file mode 100644 index 00000000000..f69a52c6386 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Glimpse/GlimpseSecurityPolicy.cs @@ -0,0 +1,32 @@ +/* +// Uncomment this class to provide custom runtime policy for Glimpse + +using Glimpse.AspNet.Extensions; +using Glimpse.Core.Extensibility; + +namespace Orchard.Glimpse +{ + public class GlimpseSecurityPolicy:IRuntimePolicy + { + public RuntimePolicy Execute(IRuntimePolicyContext policyContext) + { + // You can perform a check like the one below to control Glimpse's permissions within your application. + // More information about RuntimePolicies can be found at http://getglimpse.com/Help/Custom-Runtime-Policy + // var httpContext = policyContext.GetHttpContext(); + // if (!httpContext.User.IsInRole("Administrator")) + // { + // return RuntimePolicy.Off; + // } + + return RuntimePolicy.On; + } + + public RuntimeEvent ExecuteOn + { + // The RuntimeEvent.ExecuteResource is only needed in case you create a security policy + // Have a look at http://blog.getglimpse.com/2013/12/09/protect-glimpse-axd-with-your-custom-runtime-policy/ for more details + get { return RuntimeEvent.EndRequest | RuntimeEvent.ExecuteResource; } + } + } +} +*/ \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Glimpse/Orchard.Glimpse.csproj b/src/Orchard.Web/Modules/Orchard.Glimpse/Orchard.Glimpse.csproj index 3352e79426d..c2a9841a041 100644 --- a/src/Orchard.Web/Modules/Orchard.Glimpse/Orchard.Glimpse.csproj +++ b/src/Orchard.Web/Modules/Orchard.Glimpse/Orchard.Glimpse.csproj @@ -12,8 +12,8 @@ Properties Orchard.Glimpse Orchard.Glimpse - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -25,6 +25,7 @@ + true @@ -48,70 +49,87 @@ false + + ..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll + ..\..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll - True - - ..\..\..\packages\FluentNHibernate.2.0.3.0\lib\net40\FluentNHibernate.dll - True + + ..\..\..\packages\FluentNHibernate.3.1.0\lib\net461\FluentNHibernate.dll ..\..\..\packages\Glimpse.Ado.1.7.3\lib\net45\Glimpse.Ado.dll - True ..\..\..\packages\Glimpse.AspNet.1.9.2\lib\net45\Glimpse.AspNet.dll - True ..\..\..\packages\Glimpse.1.8.6\lib\net45\Glimpse.Core.dll - True ..\..\..\packages\Glimpse.Mvc5.1.5.3\lib\net45\Glimpse.Mvc5.dll - True - - ..\..\..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll - True + + ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll + + + ..\..\..\packages\log4net.2.0.12\lib\net45\log4net.dll + + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + + ..\..\..\packages\Microsoft.Owin.4.2.2\lib\net45\Microsoft.Owin.dll + + + ..\..\..\packages\Microsoft.Owin.Host.SystemWeb.4.2.2\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + + + ..\..\..\packages\Microsoft.Owin.Security.4.2.2\lib\net45\Microsoft.Owin.Security.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - - ..\..\..\packages\NHibernate.4.0.1.4000\lib\net40\NHibernate.dll - True + + ..\..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll + + + ..\..\..\packages\Owin.1.0\lib\net40\Owin.dll + + + ..\..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll + + + ..\..\..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll + + - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -157,6 +175,7 @@ + @@ -201,9 +220,8 @@ - - + 10.0 @@ -229,7 +247,7 @@ --> - + diff --git a/src/Orchard.Web/Modules/Orchard.Glimpse/Web.config b/src/Orchard.Web/Modules/Orchard.Glimpse/Web.config index aa6c1041eb2..0ad5a744213 100644 --- a/src/Orchard.Web/Modules/Orchard.Glimpse/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Glimpse/Web.config @@ -7,9 +7,10 @@
        +
        - + @@ -23,40 +24,34 @@ - - + - + - - + + + + + + + - - - - - + - + @@ -72,11 +67,11 @@ - + - + @@ -92,11 +87,33 @@ - + + + + + + + + - + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Glimpse/packages.config b/src/Orchard.Web/Modules/Orchard.Glimpse/packages.config index 09ab3ee1f2c..75ffcd1bc75 100644 --- a/src/Orchard.Web/Modules/Orchard.Glimpse/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Glimpse/packages.config @@ -1,15 +1,25 @@  - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ImageEditor/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.ImageEditor/Controllers/AdminController.cs index 2ae820faad0..3d096022a60 100644 --- a/src/Orchard.Web/Modules/Orchard.ImageEditor/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.ImageEditor/Controllers/AdminController.cs @@ -45,12 +45,12 @@ public ActionResult Index(int id) { [Themed(false)] public ActionResult Edit(string folderPath, string filename) { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.EditMediaContent, folderPath)) return new HttpUnauthorizedResult(); // Check permission. var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + if (!_mediaLibraryService.CanManageMediaFolder(folderPath)) { return new HttpUnauthorizedResult(); } @@ -84,7 +84,7 @@ public ActionResult Upload(int id, string content, int width, int height) { // Check permission. var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(media.FolderPath)) { + if (!Services.Authorizer.Authorize(Permissions.ImportMediaContent) && !_mediaLibraryService.CanManageMediaFolder(media.FolderPath)) { return new HttpUnauthorizedResult(); } @@ -94,6 +94,13 @@ public ActionResult Upload(int id, string content, int width, int height) { return HttpNotFound(); } + var settings = Services.WorkContext.CurrentSite.As(); + + // skip file if the allowed extensions is defined and doesn't match + if (!settings.IsFileAllowed(Path.GetFileName(media.FileName))) { + return Json(false); + } + var image = media.As(); content = content.Substring(signature.Length); diff --git a/src/Orchard.Web/Modules/Orchard.ImageEditor/Module.txt b/src/Orchard.Web/Modules/Orchard.ImageEditor/Module.txt index 1968cdfd463..29cd25331c1 100644 --- a/src/Orchard.Web/Modules/Orchard.ImageEditor/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.ImageEditor/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Adds a client side image editor for Media Library Features: Orchard.ImageEditor: diff --git a/src/Orchard.Web/Modules/Orchard.ImageEditor/Orchard.ImageEditor.csproj b/src/Orchard.Web/Modules/Orchard.ImageEditor/Orchard.ImageEditor.csproj index 15ca5c2959d..709c424ca92 100644 --- a/src/Orchard.Web/Modules/Orchard.ImageEditor/Orchard.ImageEditor.csproj +++ b/src/Orchard.Web/Modules/Orchard.ImageEditor/Orchard.ImageEditor.csproj @@ -12,8 +12,8 @@ Properties Orchard.ImageEditor Orchard.ImageEditor - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -25,6 +25,9 @@ + + + true @@ -48,10 +51,12 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -66,29 +71,23 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -117,12 +116,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {73a7688a-5bd3-4f7e-adfa-ce36c5a10e3b} @@ -184,7 +183,7 @@ - + 10.0 @@ -210,7 +209,7 @@ --> - + @@ -224,10 +223,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.ImageEditor/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.ImageEditor/Properties/AssemblyInfo.cs index 22804a3a1cf..65717aa6389 100644 --- a/src/Orchard.Web/Modules/Orchard.ImageEditor/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.ImageEditor/Properties/AssemblyInfo.cs @@ -31,6 +31,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.ImageEditor/Web.config b/src/Orchard.Web/Modules/Orchard.ImageEditor/Web.config index 67d02d6a00e..5f204e774d2 100644 --- a/src/Orchard.Web/Modules/Orchard.ImageEditor/Web.config +++ b/src/Orchard.Web/Modules/Orchard.ImageEditor/Web.config @@ -7,7 +7,7 @@ - + @@ -21,14 +21,17 @@ + + + - + - + @@ -36,25 +39,41 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.ImageEditor/packages.config b/src/Orchard.Web/Modules/Orchard.ImageEditor/packages.config index 6729ced4977..1c55d6960bb 100644 --- a/src/Orchard.Web/Modules/Orchard.ImageEditor/packages.config +++ b/src/Orchard.Web/Modules/Orchard.ImageEditor/packages.config @@ -1,7 +1,8 @@  - - - - - \ No newline at end of file + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.ImportExport/Module.txt b/src/Orchard.Web/Modules/Orchard.ImportExport/Module.txt index 29df8d1f678..a0546ca67ac 100644 --- a/src/Orchard.Web/Modules/Orchard.ImportExport/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.ImportExport/Module.txt @@ -3,8 +3,8 @@ Path: ImportExport AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Provides content item data import and export capability. Features: Orchard.ImportExport: diff --git a/src/Orchard.Web/Modules/Orchard.ImportExport/Orchard.ImportExport.csproj b/src/Orchard.Web/Modules/Orchard.ImportExport/Orchard.ImportExport.csproj index 4a1b064f8ae..77a07832d65 100644 --- a/src/Orchard.Web/Modules/Orchard.ImportExport/Orchard.ImportExport.csproj +++ b/src/Orchard.Web/Modules/Orchard.ImportExport/Orchard.ImportExport.csproj @@ -13,7 +13,8 @@ Properties Orchard.ImportExport Orchard.ImportExport - v4.5.2 + v4.8 + 7.3 false @@ -26,6 +27,9 @@ + + + true @@ -48,54 +52,59 @@ false + + ..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll + ..\..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll - True - - ..\..\..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll - True + + ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll + + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - - ..\..\..\packages\NHibernate.4.0.1.4000\lib\net40\NHibernate.dll - True + + ..\..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll + + + ..\..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll + + + ..\..\..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll + + + - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -145,16 +154,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false - - - {72457126-e118-4171-a08f-9a709ee4b7fc} - Orchard.MultiTenancy + $(MvcBuildViews) {fc1d74e8-7a4d-48f4-83de-95c6173780c4} @@ -195,7 +200,7 @@ - + 10.0 @@ -204,6 +209,14 @@ + + + $(ProjectDir)\..\Manifests + + + + + @@ -216,17 +229,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ImportExport/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.ImportExport/Properties/AssemblyInfo.cs index 24d90c2091a..9e4982f8eb9 100644 --- a/src/Orchard.Web/Modules/Orchard.ImportExport/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.ImportExport/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.ImportExport/Web.config b/src/Orchard.Web/Modules/Orchard.ImportExport/Web.config index a3cb5df907e..baf3b31252b 100644 --- a/src/Orchard.Web/Modules/Orchard.ImportExport/Web.config +++ b/src/Orchard.Web/Modules/Orchard.ImportExport/Web.config @@ -7,7 +7,7 @@ - + @@ -21,39 +21,58 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.ImportExport/packages.config b/src/Orchard.Web/Modules/Orchard.ImportExport/packages.config index 7e41029be62..5b9210e80cc 100644 --- a/src/Orchard.Web/Modules/Orchard.ImportExport/packages.config +++ b/src/Orchard.Web/Modules/Orchard.ImportExport/packages.config @@ -1,10 +1,14 @@  - - - - - - - - \ No newline at end of file + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Handlers/InfosetFieldIndexingHandler.cs b/src/Orchard.Web/Modules/Orchard.Indexing/Handlers/InfosetFieldIndexingHandler.cs index f9a8ea469f0..86ea2a0310a 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Handlers/InfosetFieldIndexingHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Handlers/InfosetFieldIndexingHandler.cs @@ -32,7 +32,8 @@ public InfosetFieldIndexingHandler( // part fields foreach ( var part in infosetPart.ContentItem.Parts ) { foreach ( var field in part.PartDefinition.Fields ) { - if (!field.Settings.GetModel().Included) { + var indexingSettings = field.Settings.GetModel(); + if (!indexingSettings.Included) { continue; } @@ -45,7 +46,7 @@ public InfosetFieldIndexingHandler( var fieldStorage = _fieldStorageProvider.BindStorage(localPart, localField); var indexName = infosetPart.TypeDefinition.Name.ToLower() + "-" + field.Name.ToLower(); - var membersContext = new DescribeMembersContext(fieldStorage, values => { + var membersContext = new DescribeMembersContext(null, fieldStorage, values => { foreach (var value in values) { @@ -62,16 +63,17 @@ public InfosetFieldIndexingHandler( var typeCode = Type.GetTypeCode(t); + IDocumentIndex documentIndex = null; switch (typeCode) { case TypeCode.Empty: case TypeCode.Object: case TypeCode.DBNull: case TypeCode.String: case TypeCode.Char: - context.DocumentIndex.Add(indexName, Convert.ToString(value)).RemoveTags().Analyze(); + documentIndex = context.DocumentIndex.Add(indexName, Convert.ToString(value)); break; case TypeCode.Boolean: - context.DocumentIndex.Add(indexName, Convert.ToBoolean(value)); + documentIndex = context.DocumentIndex.Add(indexName, Convert.ToBoolean(value)); break; case TypeCode.SByte: case TypeCode.Int16: @@ -80,19 +82,37 @@ public InfosetFieldIndexingHandler( case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: - context.DocumentIndex.Add(indexName, Convert.ToInt32(value)); + documentIndex = context.DocumentIndex.Add(indexName, Convert.ToInt32(value)); break; case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: - context.DocumentIndex.Add(indexName, Convert.ToDouble(value)); + documentIndex = context.DocumentIndex.Add(indexName, Convert.ToDouble(value)); break; case TypeCode.DateTime: - context.DocumentIndex.Add(indexName, Convert.ToDateTime(value)); + documentIndex = context.DocumentIndex.Add(indexName, Convert.ToDateTime(value)); break; } + + if(documentIndex == null) { + // Protection against none of the case statements above being matched + return; + } + + if (indexingSettings.Stored) { + documentIndex.Store(); + } + + if (indexingSettings.Analyzed) { + documentIndex.Analyze(); + } + + if (indexingSettings.TagsRemoved) { + documentIndex.RemoveTags(); + } + } - }); + }, localField); foreach (var driver in drivers) { driver.Describe(membersContext); diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Module.txt b/src/Orchard.Web/Modules/Orchard.Indexing/Module.txt index 8141f7adc23..4e0cd819ed4 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: The Indexing module enables the site to be indexed. The index generated by this module can then be used by the search module to provide an integrated full-text search experience to a web site. FeatureDescription: Indexing infrastructure. Requires an index implementation like the Lucene module. Category: Search diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Orchard.Indexing.csproj b/src/Orchard.Web/Modules/Orchard.Indexing/Orchard.Indexing.csproj index 9646669cf24..306ee2ebf05 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Orchard.Indexing.csproj +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Orchard.Indexing.csproj @@ -12,7 +12,8 @@ Properties Orchard.Indexing Orchard.Indexing - v4.5.2 + v4.8 + 7.3 @@ -26,6 +27,9 @@ + + + true @@ -49,10 +53,12 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -62,28 +68,22 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -105,6 +105,7 @@ + @@ -125,10 +126,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core + $(MvcBuildViews) @@ -143,7 +146,7 @@ - + 10.0 @@ -152,6 +155,14 @@ + + + $(ProjectDir)\..\Manifests + + + + + @@ -164,17 +175,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Indexing/Properties/AssemblyInfo.cs index 7ed563bac34..722a266a0e0 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Scripts/FieldIndexing.js b/src/Orchard.Web/Modules/Orchard.Indexing/Scripts/FieldIndexing.js new file mode 100644 index 00000000000..08407078f1d --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Scripts/FieldIndexing.js @@ -0,0 +1,3 @@ +$(".indexing-controlling-checkbox").change(function () { + $("[data-indexing-controlled-by*='" + $(this).attr("name") + "']").toggle($(this).prop("checked")); +}).trigger("change"); \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Scripts/Web.config b/src/Orchard.Web/Modules/Orchard.Indexing/Scripts/Web.config new file mode 100644 index 00000000000..93eab9a7372 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Scripts/Web.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexingNoLockTableProvider.cs b/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexingNoLockTableProvider.cs new file mode 100644 index 00000000000..c8dcbd6bb1d --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexingNoLockTableProvider.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using Orchard.Data.Providers; + +namespace Orchard.Indexing.Services { + public class IndexingNoLockTableProvider : INoLockTableProvider { + public IEnumerable GetTableNames() { + return new string[] { "Orchard_Indexing_IndexingTaskRecord" }; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexingTaskExecutor.cs b/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexingTaskExecutor.cs index 91266c902bf..2833d5a593d 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexingTaskExecutor.cs +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexingTaskExecutor.cs @@ -20,8 +20,7 @@ namespace Orchard.Indexing.Services { /// This class is synchronized using a lock file as both command line and web workers can potentially use it, /// and singleton locks would not be shared accross those two. /// - public class IndexingTaskExecutor : IIndexingTaskExecutor, IIndexStatisticsProvider - { + public class IndexingTaskExecutor : IIndexingTaskExecutor, IIndexStatisticsProvider { private readonly IRepository _taskRepository; private readonly IRepository _contentRepository; private IIndexProvider _indexProvider; @@ -160,10 +159,22 @@ private bool BatchIndex(string indexName, string settingsFilename, IndexSettings .OrderBy(versionRecord => versionRecord.Id) .Take(ContentItemsPerLoop) .ToList() - .Select(versionRecord => _contentManager.Get(versionRecord.ContentItemRecord.Id, VersionOptions.VersionRecord(versionRecord.Id))) + .Select(versionRecord => { + try { + // In some rare cases a ContentItemVersionRecord without a ContentItemRecord can end up in the DB. + // in that case ContentManager throws a ObjectNotFoundException. + // e.g. NHibernate.ObjectNotFoundException: No row with the given identifier exists[Orchard.ContentManagement.Records.ContentItemRecord#148] + return _contentManager.Get(versionRecord.ContentItemRecord.Id, VersionOptions.VersionRecord(versionRecord.Id)); + } + catch { + return null; + } + }) + // In some rare cases a ContentItemRecord without a ContentType can end up in the DB. + // We need to filter out such records, otherwise they will crash the ContentManager. + .Where(content => content != null && content.ContentType != null) .Distinct() .ToList(); - // if no more elements to index, switch to update mode if (contentItems.Count == 0) { indexSettings.Mode = IndexingMode.Update; @@ -220,8 +231,25 @@ private bool BatchIndex(string indexName, string settingsFilename, IndexSettings .OrderBy(x => x.Id) .Take(ContentItemsPerLoop) .ToList() + .Where(x => x.ContentItemRecord != null) .GroupBy(x => x.ContentItemRecord.Id) - .Select(group => new { TaskId = group.Max(task => task.Id), Delete = group.Last().Action == IndexingTaskRecord.Delete, Id = group.Key, ContentItem = _contentManager.Get(group.Key, VersionOptions.Latest) }) + .Select(group => new { + TaskId = group.Max(task => task.Id), + Delete = group.Last().Action == IndexingTaskRecord.Delete, + Id = group.Key, + // We can only have a ContentItem if the ContentItemRecord matches + // something that still exists in our records. + ContentItem = group.All(x => { + try { + return x.ContentItemRecord != null + // ContentType is required to build the ContentItem + && x.ContentItemRecord.ContentType != null; + } + catch { + return false; + } + }) ? _contentManager.Get(group.Key, VersionOptions.Latest) : null // Set to null to "tell" it's a delete/destroy + }) .OrderBy(x => x.TaskId) .ToArray(); @@ -308,12 +336,10 @@ private bool BatchIndex(string indexName, string settingsFilename, IndexSettings /// /// Loads the settings file or create a new default one if it doesn't exist /// - public IndexSettings LoadSettings(string indexName) - { + public IndexSettings LoadSettings(string indexName) { var indexSettings = new IndexSettings(); var settingsFilename = GetSettingsFileName(indexName); - if (_appDataFolder.FileExists(settingsFilename)) - { + if (_appDataFolder.FileExists(settingsFilename)) { var content = _appDataFolder.ReadFile(settingsFilename); indexSettings = IndexSettings.Parse(content); } @@ -332,7 +358,7 @@ public void DeleteSettings(string indexName) { } /// - /// Creates a IDocumentIndex instance for a specific content item id. If the content + /// Creates a IDocumentIndex instance for a specific content item id. If the content /// item is no more published, it returns null. /// private IDocumentIndex ExtractDocumentIndex(ContentItem contentItem) { @@ -352,7 +378,7 @@ private static TypeIndexing GetTypeIndexingSettings(ContentItem contentItem) { if (contentItem == null || contentItem.TypeDefinition == null || contentItem.TypeDefinition.Settings == null) { - return new TypeIndexing {Indexes = ""}; + return new TypeIndexing { Indexes = "" }; } return contentItem.TypeDefinition.Settings.GetModel(); } diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Settings/EditorEvents.cs b/src/Orchard.Web/Modules/Orchard.Indexing/Settings/EditorEvents.cs index 6ec0cd3a0b4..82db99a6caf 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Settings/EditorEvents.cs +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Settings/EditorEvents.cs @@ -66,13 +66,19 @@ public override IEnumerable PartFieldEditor(ContentPartFieldD public override IEnumerable PartFieldEditorUpdate(ContentPartFieldDefinitionBuilder builder, IUpdateModel updateModel) { var previous = builder.Current.Settings.GetModel(); - + var model = new FieldIndexing(); updateModel.TryUpdateModel(model, "FieldIndexing", null, null); builder.WithSetting("FieldIndexing.Included", model.Included ? true.ToString() : null); + builder.WithSetting("FieldIndexing.Stored", model.Stored.ToString()); + builder.WithSetting("FieldIndexing.Analyzed", model.Analyzed.ToString()); + builder.WithSetting("FieldIndexing.TagsRemoved", model.TagsRemoved.ToString()); // create indexing tasks only if settings have changed - if (model.Included != previous.Included) { + if (model.Included != previous.Included || + model.Stored != previous.Stored || + model.Analyzed != previous.Analyzed || + model.TagsRemoved != previous.TagsRemoved) { // if a field setting has changed, all existing content items need to be re-indexed CreateIndexingTasks(); diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Settings/FieldIndexing.cs b/src/Orchard.Web/Modules/Orchard.Indexing/Settings/FieldIndexing.cs index ba465282286..011b5f45592 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Settings/FieldIndexing.cs +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Settings/FieldIndexing.cs @@ -1,5 +1,13 @@ namespace Orchard.Indexing.Settings { public class FieldIndexing { + public FieldIndexing() { + Analyzed = true; + TagsRemoved = true; + } + public bool Included { get; set; } + public bool Stored { get; set; } + public bool Analyzed { get; set; } + public bool TagsRemoved { get; set; } } } diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/FieldIndexing.cshtml b/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/FieldIndexing.cshtml index d274364e96e..c10108fb1d0 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/FieldIndexing.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/FieldIndexing.cshtml @@ -1,10 +1,30 @@ @model Orchard.Indexing.Settings.FieldIndexing +@{ + Script.Include("FieldIndexing.js").AtFoot(); +} +
        + @T("Indexing")
        - @Html.EditorFor(m=>m.Included) + @Html.CheckBoxFor(m => m.Included, new { @class = "indexing-controlling-checkbox" }) @Html.ValidationMessageFor(m => m.Included) @T("Check to add content of this field in the selected indexes.")
        +
        + @Html.CheckBoxFor(m => m.Stored) + + @Html.ValidationMessageFor(m => m.Stored) +
        +
        + @Html.CheckBoxFor(m => m.Analyzed) + + @Html.ValidationMessageFor(m => m.Analyzed) +
        +
        + @Html.CheckBoxFor(m => m.TagsRemoved) + + @Html.ValidationMessageFor(m => m.TagsRemoved) +
        \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Web.config b/src/Orchard.Web/Modules/Orchard.Indexing/Web.config index a3cb5df907e..baf3b31252b 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Web.config @@ -7,7 +7,7 @@ - + @@ -21,39 +21,58 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/packages.config b/src/Orchard.Web/Modules/Orchard.Indexing/packages.config index 6729ced4977..1c55d6960bb 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Indexing/packages.config @@ -1,7 +1,8 @@  - - - - - \ No newline at end of file + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.JobsQueue/Module.txt b/src/Orchard.Web/Modules/Orchard.JobsQueue/Module.txt index b9dc23426da..3b623f5e082 100644 --- a/src/Orchard.Web/Modules/Orchard.JobsQueue/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.JobsQueue/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: This module provides a jobs queue to process jobs asynchronously. Features: Orchard.JobsQueue: diff --git a/src/Orchard.Web/Modules/Orchard.JobsQueue/Orchard.JobsQueue.csproj b/src/Orchard.Web/Modules/Orchard.JobsQueue/Orchard.JobsQueue.csproj index 6a87cbf78ff..777c557625d 100644 --- a/src/Orchard.Web/Modules/Orchard.JobsQueue/Orchard.JobsQueue.csproj +++ b/src/Orchard.Web/Modules/Orchard.JobsQueue/Orchard.JobsQueue.csproj @@ -13,7 +13,8 @@ Properties Orchard.JobsQueue Orchard.JobsQueue - v4.5.2 + v4.8 + 7.3 @@ -27,6 +28,9 @@ + + +
        true @@ -50,13 +54,14 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - - ..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True + + ..\..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll @@ -68,28 +73,22 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -130,12 +129,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839c-39fc-4ceb-a5af-89ca7e87119f} Orchard.Core - false + $(MvcBuildViews) {642a49d7-8752-4177-80d6-bfbbcfad3de0} @@ -162,7 +161,7 @@ - + 10.0 @@ -171,6 +170,14 @@ + + + $(ProjectDir)\..\Manifests + + + + + @@ -183,17 +190,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.JobsQueue/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.JobsQueue/Properties/AssemblyInfo.cs index da7e0dad686..ad7a83e3932 100644 --- a/src/Orchard.Web/Modules/Orchard.JobsQueue/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.JobsQueue/Properties/AssemblyInfo.cs @@ -31,6 +31,6 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.JobsQueue/Tests/Orchard.Messaging.Tests.csproj b/src/Orchard.Web/Modules/Orchard.JobsQueue/Tests/Orchard.Messaging.Tests.csproj index 4205ce931d5..9dcd5c4e935 100644 --- a/src/Orchard.Web/Modules/Orchard.JobsQueue/Tests/Orchard.Messaging.Tests.csproj +++ b/src/Orchard.Web/Modules/Orchard.JobsQueue/Tests/Orchard.Messaging.Tests.csproj @@ -10,7 +10,7 @@ Properties Orchard.Messaging.Tests Orchard.Messaging.Tests - v4.5 + v4.8 512 @@ -42,9 +42,8 @@ False ..\..\..\..\..\lib\moq\Moq.dll - - False - ..\..\..\..\..\lib\newtonsoft.json\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dllHintPath> ..\..\..\..\..\lib\nunit\nunit.framework.dll diff --git a/src/Orchard.Web/Modules/Orchard.JobsQueue/Web.config b/src/Orchard.Web/Modules/Orchard.JobsQueue/Web.config index a3cb5df907e..fd7fac8e5c2 100644 --- a/src/Orchard.Web/Modules/Orchard.JobsQueue/Web.config +++ b/src/Orchard.Web/Modules/Orchard.JobsQueue/Web.config @@ -7,7 +7,7 @@ - + @@ -21,39 +21,59 @@ + + + - + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.JobsQueue/packages.config b/src/Orchard.Web/Modules/Orchard.JobsQueue/packages.config index 1ea27eef99b..d8ef6eca5c4 100644 --- a/src/Orchard.Web/Modules/Orchard.JobsQueue/packages.config +++ b/src/Orchard.Web/Modules/Orchard.JobsQueue/packages.config @@ -1,8 +1,9 @@  - - - - - - \ No newline at end of file + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/LayoutEditor/Directives/Editor.js b/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/LayoutEditor/Directives/Editor.js index b7dcde8aa7d..cbe373b5fd9 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/LayoutEditor/Directives/Editor.js +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/LayoutEditor/Directives/Editor.js @@ -97,6 +97,9 @@ break; case "paste": focusedElement.paste(e.originalEvent.clipboardData); + $.event.trigger({ + type: "layouteditor:edited" + }); break; } }); diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/LayoutEditor/Directives/Toolbox.js b/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/LayoutEditor/Directives/Toolbox.js index 2bb2f7772b4..5655ac3014a 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/LayoutEditor/Directives/Toolbox.js +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/LayoutEditor/Directives/Toolbox.js @@ -145,6 +145,8 @@ connectWith: _(parentClasses).map(function (e) { return "#" + editorId + " " + e + ":not(.layout-container-sealed) > .layout-element-wrapper > .layout-children"; }).join(", "), placeholder: placeholderClasses, "ui-floating": floating, + helper: "clone", // We clone the element and we append it to the body because the container overflow is set to auto (see: Assets\Less\LayoutEditor\Toolbox.less) and otherwise it could not be moved with drag&drop + appendTo: "body", create: function (e, ui) { e.target.isToolbox = true; // Will indicate to connected sortables that dropped items were sent from toolbox. }, @@ -179,29 +181,7 @@ } ], templateUrl: environment.templateUrl("Toolbox"), - replace: true, - link: function (scope, element) { - var toolbox = element.find(".layout-toolbox"); - $(window).on("resize scroll", function (e) { - var canvas = element.parent().find(".layout-canvas"); - // If the canvas is taller than the toolbox, make the toolbox sticky-positioned within the editor - // to help the user avoid excessive vertical scrolling. - var canvasIsTaller = !!canvas && canvas.height() > toolbox.height(); - var windowPos = $(window).scrollTop(); - if (canvasIsTaller && windowPos > element.offset().top + element.height() - toolbox.height()) { - toolbox.addClass("sticky-bottom"); - toolbox.removeClass("sticky-top"); - } - else if (canvasIsTaller && windowPos > element.offset().top) { - toolbox.addClass("sticky-top"); - toolbox.removeClass("sticky-bottom"); - } - else { - toolbox.removeClass("sticky-top"); - toolbox.removeClass("sticky-bottom"); - } - }); - } + replace: true }; } ]); \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/LayoutEditor/Services/ScopeConfigurator.js b/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/LayoutEditor/Services/ScopeConfigurator.js index 13f9bdf0672..81a46cd599f 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/LayoutEditor/Services/ScopeConfigurator.js +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/LayoutEditor/Services/ScopeConfigurator.js @@ -149,11 +149,14 @@ $scope.delete = function (element) { element.delete(); + $.event.trigger({ + type: "layouteditor:edited" + }); } if ($scope.element.hasEditor) { $scope.edit = function () { - $scope.$root.editElement($scope.element).then(function (args) { + $scope.$root.editElement($scope.element).done(function (args) { $scope.$apply(function () { if (args.cancel) return; @@ -255,7 +258,7 @@ receivedElement.setParent(element); if (!!receivedElement.hasEditor) { - $scope.$root.editElement(receivedElement).then(function (args) { + $scope.$root.editElement(receivedElement).done(function (args) { if (!args.cancel) { receivedElement.data = args.element.data; receivedElement.applyElementEditorModel(args.elementEditorModel); @@ -281,6 +284,10 @@ element.setIsDropTarget(false); if (!!receivedElement) receivedElement.setIsFocused(); + + $scope.$root.addElement(receivedElement).done(function () { + return; + }); }); }); } diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/Models/Container.js b/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/Models/Container.js index ffb0566cc99..14af93cc90c 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/Models/Container.js +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/Models/Container.js @@ -92,6 +92,9 @@ return; var index = _(this.children).indexOf(child); this.children.move(index, index - 1); + $.event.trigger({ + type: "layouteditor:edited" + }); }; this.moveChildDown = function (child) { @@ -99,6 +102,9 @@ return; var index = _(this.children).indexOf(child); this.children.move(index, index + 1); + $.event.trigger({ + type: "layouteditor:edited" + }); }; this.canMoveChildUp = function (child) { diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Assets/Less/LayoutEditor/Editor.less b/src/Orchard.Web/Modules/Orchard.Layouts/Assets/Less/LayoutEditor/Editor.less index 35cb262b36d..258feafb75b 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Assets/Less/LayoutEditor/Editor.less +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Assets/Less/LayoutEditor/Editor.less @@ -19,10 +19,10 @@ display: flex; margin-top: 1em; font-size: @font-size; - align-items: stretch; > .layout-canvas-wrapper { - flex-grow: 1; + flex: 1 1; + height: fit-content; background-color: @gray-bg; border: 1px solid @gray-border; diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Assets/Less/LayoutEditor/Toolbox.less b/src/Orchard.Web/Modules/Orchard.Layouts/Assets/Less/LayoutEditor/Toolbox.less index 931abb59e65..0b3971e2160 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Assets/Less/LayoutEditor/Toolbox.less +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Assets/Less/LayoutEditor/Toolbox.less @@ -1,39 +1,48 @@ @import "Variables.less"; +body { + .layout-toolbox-item { + border: 1px solid @gray-border; + background-color: #fff; + padding: (@container-padding - 3) @container-padding; + cursor: default; + list-style-type: none; + + i { + display: inline-block; + width: 16px; + font: normal normal normal 14px/1 FontAwesome; + } + + + .layout-toolbox-item { + margin-top: @container-padding / 3; + } + } +} + .layout-editor { > .layout-toolbox-wrapper { - position: relative; - margin-left: @container-padding; + position: sticky; + top: 1vh; + padding-left: @container-padding; width: 220px; - flex-shrink: 0; + overflow-y: auto; + scrollbar-width: thin; + min-height: 400px; + max-height: 98vh; + height: 100%; > .layout-toolbox { border: 1px solid @gray-border; - width: 220px; - min-height: 400px; padding: @container-padding / 2; background-color: @gray-bg; - &.sticky-top { - position: fixed; - top: 0; - max-height: 100%; - overflow-y: auto; - } - - &.sticky-bottom { - position: absolute; - bottom: 0; - } - .layout-toolbox-group { - margin-top: @container-padding; - .layout-toolbox-group-heading { display: block; margin-bottom: @container-padding / 3; text-decoration: none; - + &:before { display: inline-block; width: 10px; @@ -43,7 +52,7 @@ content: "\f0d7"; } } - + &.collapsed { .layout-toolbox-group-heading:before { content: "\f0da"; diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Controllers/ElementController.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Controllers/ElementController.cs index edacf6f91ad..469b4b86d73 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Controllers/ElementController.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Controllers/ElementController.cs @@ -30,8 +30,8 @@ public ElementController( IElementManager elementManager, IShapeFactory shapeFactory, ITransactionManager transactionManager, - IContentManager contentManager, - IObjectStore objectStore, + IContentManager contentManager, + IObjectStore objectStore, IShapeDisplay shapeDisplay, ILayoutModelMapper mapper) { @@ -57,9 +57,10 @@ public RedirectToRouteResult Edit(string session, string typeName, string elemen }; _objectStore.Set(session, state); - return RedirectToAction("Edit", new {session}); + + return RedirectToAction("Edit", new { session }); } - + public ViewResult Edit(string session) { var sessionState = _objectStore.Get(session); var contentId = sessionState.ContentId; @@ -151,9 +152,7 @@ private DescribeElementsContext CreateDescribeContext(int? contentId = null, str if (contentId == null && contentType == null) return DescribeElementsContext.Empty; - var part = contentId != null && contentId != 0 ? _contentManager.Get(contentId.Value) - ?? _contentManager.New(contentType) - : _contentManager.New(contentType); + var part = _contentManager.Get(contentId.Value, VersionOptions.Latest) ?? _contentManager.New(contentType); return new DescribeElementsContext { Content = part @@ -172,4 +171,4 @@ void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) { ModelState.AddModelError(key, errorMessage.Text); } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ElementWrapperPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ElementWrapperPartDriver.cs index 2f73ed98442..fc0c695a770 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ElementWrapperPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ElementWrapperPartDriver.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics.Eventing.Reader; using System.Linq; using Orchard.ContentManagement; using Orchard.ContentManagement.Drivers; @@ -91,11 +90,10 @@ protected override void Exporting(ElementWrapperPart part, ExportContentContext protected override void Exported(ElementWrapperPart part, ExportContentContext context) { var describeContext = CreateDescribeContext(part); - var descriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, part.ElementTypeName); - var data = ElementDataHelper.Deserialize(part.ElementData); - var element = _elementManager.ActivateElement(descriptor, e => e.Data = data); - - _elementManager.Exported(new[] { element }, new ExportLayoutContext()); + // Deserialize element from the version set in the Exporting method + var currentContextValue = context.Element(part.PartDefinition.Name).Value; + var element = _serializer.Deserialize(currentContextValue, describeContext); + _elementManager.Exported(new[] {element}, new ExportLayoutContext()); var exportableData = _serializer.Serialize(element); context.Element(part.PartDefinition.Name).SetValue(exportableData); @@ -108,22 +106,38 @@ protected override void Importing(ElementWrapperPart part, ImportContentContext } protected override void Imported(ElementWrapperPart part, ImportContentContext context) { - HandleImportEvent(part, context, (describeContext, element) => { + HandleSecondaryImportEvent(part, context, (describeContext, element) => { _elementManager.Imported(new[] { element }, new ImportLayoutContext { Session = new ImportContentContextWrapper(context) }); }); } protected override void ImportCompleted(ElementWrapperPart part, ImportContentContext context) { - HandleImportEvent(part, context, (describeContext, element) => { + HandleSecondaryImportEvent(part, context, (describeContext, element) => { _elementManager.ImportCompleted(new[] { element }, new ImportLayoutContext { Session = new ImportContentContextWrapper(context) }); }); } - private void HandleImportEvent(ElementWrapperPart part, ImportContentContext context, Action callback) { + private void HandleSecondaryImportEvent(ElementWrapperPart part, ImportContentContext context, Action callback) { var root = context.Data.Element(part.PartDefinition.Name); + if (root == null) { + return; + } - if (root == null) + var describeContext = CreateDescribeContext(part); + // Deserialize element from the data set in previous Import events + var descriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, part.ElementTypeName); + var data = ElementDataHelper.Deserialize(part.ElementData); + var element = _elementManager.ActivateElement(descriptor, e => e.Data = data); + + callback(describeContext, element); + part.ElementData = element.Data.Serialize(); + } + + private void HandleImportEvent(ElementWrapperPart part, ImportContentContext context, Action callback) { + var root = context.Data.Element(part.PartDefinition.Name); + if (root == null) { return; + } var exportedData = root.Value; var describeContext = CreateDescribeContext(part); diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HeadingElementDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HeadingElementDriver.cs index 0bc14c531e9..d122e6eb57a 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HeadingElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HeadingElementDriver.cs @@ -2,15 +2,15 @@ using Orchard.Layouts.Framework.Display; using Orchard.Layouts.Framework.Drivers; using Orchard.Layouts.Helpers; -using Orchard.Layouts.Services; using Orchard.Layouts.ViewModels; +using Orchard.Services; namespace Orchard.Layouts.Drivers { public class HeadingElementDriver : ElementDriver { - private readonly IElementFilterProcessor _processor; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; - public HeadingElementDriver(IElementFilterProcessor processor) { - _processor = processor; + public HeadingElementDriver(IHtmlFilterProcessor htmlFilterProcessor) { + _htmlFilterProcessor = htmlFilterProcessor; } protected override EditorResult OnBuildEditor(Heading element, ElementEditorContext context) { @@ -30,7 +30,7 @@ protected override EditorResult OnBuildEditor(Heading element, ElementEditorCont } protected override void OnDisplaying(Heading element, ElementDisplayingContext context) { - context.ElementShape.ProcessedContent = _processor.ProcessContent(element.Content, "html", context.GetTokenData()); + context.ElementShape.ProcessedContent = _htmlFilterProcessor.ProcessFilters(element.Content, new HtmlFilterContext { Flavor = "html", Data = context.GetTokenData() }); context.ElementShape.Level = element.Level; } } diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HtmlElementDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HtmlElementDriver.cs index 09d877c5be3..8e7c050b6ca 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HtmlElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HtmlElementDriver.cs @@ -2,20 +2,22 @@ using Orchard.Layouts.Framework.Display; using Orchard.Layouts.Framework.Drivers; using Orchard.Layouts.Helpers; -using Orchard.Layouts.Services; using Orchard.Layouts.ViewModels; +using Orchard.Services; -namespace Orchard.Layouts.Drivers { +namespace Orchard.Layouts.Drivers +{ public class HtmlElementDriver : ElementDriver { - private readonly IElementFilterProcessor _processor; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; - public HtmlElementDriver(IElementFilterProcessor processor) { - _processor = processor; + public HtmlElementDriver(IHtmlFilterProcessor htmlFilterProcessor) { + _htmlFilterProcessor = htmlFilterProcessor; } protected override EditorResult OnBuildEditor(Html element, ElementEditorContext context) { var viewModel = new HtmlEditorViewModel { - Text = element.Content + Text = element.Content, + Part = ((dynamic)context.Content.ContentItem).LayoutPart }; var editor = context.ShapeFactory.EditorTemplate(TemplateName: "Elements.Html", Model: viewModel); @@ -28,7 +30,7 @@ protected override EditorResult OnBuildEditor(Html element, ElementEditorContext } protected override void OnDisplaying(Html element, ElementDisplayingContext context) { - context.ElementShape.ProcessedContent = _processor.ProcessContent(element.Content, "html", context.GetTokenData()); + context.ElementShape.ProcessedContent = _htmlFilterProcessor.ProcessFilters(element.Content, new HtmlFilterContext { Flavor = "html", Data = context.GetTokenData() }); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/LayoutPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/LayoutPartDriver.cs index ee09915c68f..b9d33f0134d 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/LayoutPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/LayoutPartDriver.cs @@ -204,7 +204,7 @@ private string WriteFormattedLayoutData(string layoutDataString) { var layoutData = JsonConvert.DeserializeObject(layoutDataString); var formattedLayoutData = JsonConvert.SerializeObject(layoutData, Formatting.Indented); - return $"\n{formattedLayoutData}\n"; + return String.Format("\n{0}\n", formattedLayoutData); } private string ReadFormattedLayoutData(string formattedLayoutData) diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/MarkdownElementDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/MarkdownElementDriver.cs index e988c89a17d..8e7f8d612e9 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/MarkdownElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/MarkdownElementDriver.cs @@ -2,16 +2,17 @@ using Orchard.Layouts.Framework.Display; using Orchard.Layouts.Framework.Drivers; using Orchard.Layouts.Helpers; -using Orchard.Layouts.Services; using Orchard.Layouts.ViewModels; +using Orchard.Services; using MarkdownElement = Orchard.Layouts.Elements.Markdown; -namespace Orchard.Layouts.Drivers { +namespace Orchard.Layouts.Drivers +{ [OrchardFeature("Orchard.Layouts.Markdown")] public class MarkdownElementDriver : ElementDriver { - private readonly IElementFilterProcessor _processor; - public MarkdownElementDriver(IElementFilterProcessor processor) { - _processor = processor; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; + public MarkdownElementDriver(IHtmlFilterProcessor htmlFilterProcessor) { + _htmlFilterProcessor = htmlFilterProcessor; } protected override EditorResult OnBuildEditor(MarkdownElement element, ElementEditorContext context) { @@ -29,7 +30,7 @@ protected override EditorResult OnBuildEditor(MarkdownElement element, ElementEd } protected override void OnDisplaying(MarkdownElement element, ElementDisplayingContext context) { - context.ElementShape.ProcessedContent = _processor.ProcessContent(element.Content, "markdown", context.GetTokenData()); + context.ElementShape.ProcessedContent = _htmlFilterProcessor.ProcessFilters(element.Content, new HtmlFilterContext { Flavor = "markdown", Data = context.GetTokenData() }); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ParagraphElementDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ParagraphElementDriver.cs index 0d285207ad5..1aca94f2a77 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ParagraphElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ParagraphElementDriver.cs @@ -2,15 +2,15 @@ using Orchard.Layouts.Framework.Display; using Orchard.Layouts.Framework.Drivers; using Orchard.Layouts.Helpers; -using Orchard.Layouts.Services; using Orchard.Layouts.ViewModels; +using Orchard.Services; namespace Orchard.Layouts.Drivers { public class ParagraphElementDriver : ElementDriver { - private readonly IElementFilterProcessor _processor; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; - public ParagraphElementDriver(IElementFilterProcessor processor) { - _processor = processor; + public ParagraphElementDriver(IHtmlFilterProcessor htmlFilterProcessor) { + _htmlFilterProcessor = htmlFilterProcessor; } protected override EditorResult OnBuildEditor(Paragraph element, ElementEditorContext context) { @@ -28,7 +28,7 @@ protected override EditorResult OnBuildEditor(Paragraph element, ElementEditorCo } protected override void OnDisplaying(Paragraph element, ElementDisplayingContext context) { - context.ElementShape.ProcessedContent = _processor.ProcessContent(element.Content, "html", context.GetTokenData()); + context.ElementShape.ProcessedContent = _htmlFilterProcessor.ProcessFilters(element.Content, new HtmlFilterContext { Flavor = "html", Data = context.GetTokenData() }); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ShapeElementDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ShapeElementDriver.cs index 1d25f13f2c1..5f54715ee5e 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ShapeElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ShapeElementDriver.cs @@ -37,11 +37,11 @@ protected override void DescribeForm(DescribeContext context) { Id: "shapeType", Name: "ShapeType", Title: T("Shape Type"), - Description: T("The shape type name to dislay."), + Description: T("The shape type name to display."), Classes: new[] { "text", "large", "tokenized" })); return form; }); } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/TextElementDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/TextElementDriver.cs index e85dad82c9c..87083dd7d6b 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/TextElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/TextElementDriver.cs @@ -2,15 +2,16 @@ using Orchard.Layouts.Framework.Display; using Orchard.Layouts.Framework.Drivers; using Orchard.Layouts.Helpers; -using Orchard.Layouts.Services; using Orchard.Layouts.ViewModels; +using Orchard.Services; -namespace Orchard.Layouts.Drivers { +namespace Orchard.Layouts.Drivers +{ public class TextElementDriver : ElementDriver { - private readonly IElementFilterProcessor _processor; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; - public TextElementDriver(IElementFilterProcessor processor) { - _processor = processor; + public TextElementDriver(IHtmlFilterProcessor htmlFilterProcessor) { + _htmlFilterProcessor = htmlFilterProcessor; } protected override EditorResult OnBuildEditor(Text element, ElementEditorContext context) { @@ -28,7 +29,7 @@ protected override EditorResult OnBuildEditor(Text element, ElementEditorContext } protected override void OnDisplaying(Text element, ElementDisplayingContext context) { - context.ElementShape.ProcessedContent = _processor.ProcessContent(element.Content, "textarea", context.GetTokenData()); + context.ElementShape.ProcessedContent = _htmlFilterProcessor.ProcessFilters(element.Content, new HtmlFilterContext { Flavor = "textarea", Data = context.GetTokenData() }); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Elements/Snippet.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Elements/Snippet.cs index 79df291fce5..7e4eb18a66d 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Elements/Snippet.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Elements/Snippet.cs @@ -1,6 +1,5 @@ using Orchard.Environment.Extensions; using Orchard.Layouts.Framework.Elements; -using Orchard.Localization; namespace Orchard.Layouts.Elements { [OrchardFeature("Orchard.Layouts.Snippets")] diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Filters/TokensFilter.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Filters/TokensFilter.cs deleted file mode 100644 index 1dc8a27a5c5..00000000000 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Filters/TokensFilter.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using Orchard.Environment.Extensions; -using Orchard.Layouts.Services; -using Orchard.Tokens; -using System.Collections.Generic; - -namespace Orchard.Layouts.Filters { - [OrchardFeature("Orchard.Layouts.Tokens")] - public class TokensFilter : IElementFilter { - - private readonly ITokenizer _tokenizer; - - public TokensFilter(ITokenizer tokenizer) { - _tokenizer = tokenizer; - } - - public string ProcessContent(string text, string flavor) { - return ProcessContent(text, flavor, new Dictionary()); - } - - public string ProcessContent(string text, string flavor, IDictionary context) { - if (String.IsNullOrEmpty(text)) - return ""; - - if (!text.Contains("#{")) { - return text; - } - - text = _tokenizer.Replace(text, context, new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); - - return text; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Harvesters/HarvestElementsContext.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Harvesters/HarvestElementsContext.cs index c8cc7c230ac..a30249306b9 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Harvesters/HarvestElementsContext.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Framework/Harvesters/HarvestElementsContext.cs @@ -3,5 +3,6 @@ namespace Orchard.Layouts.Framework.Harvesters { public class HarvestElementsContext { public IContent Content { get; set; } + public bool IsHarvesting { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Helpers/SnippetHtmlExtensions.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Helpers/SnippetHtmlExtensions.cs index d6b40ab2d04..293a1581e3e 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Helpers/SnippetHtmlExtensions.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Helpers/SnippetHtmlExtensions.cs @@ -7,9 +7,9 @@ namespace Orchard.Layouts.Helpers { public static class SnippetHtmlExtensions { - + public static SnippetFieldDescriptorBuilder SnippetField(this HtmlHelper htmlHelper, string name, string type = null) { - var shape = (dynamic) htmlHelper.ViewData.Model; + var shape = (dynamic)htmlHelper.ViewData.Model; return new SnippetFieldDescriptorBuilder(shape) .Named(name) @@ -47,17 +47,11 @@ public SnippetFieldDescriptorBuilder WithDescription(LocalizedString value) { } public override string ToString() { - var registratorCallback = (Action)_shape.DescriptorRegistrationCallback; - - if (registratorCallback != null) - registratorCallback(Descriptor); + ((Action)_shape.DescriptorRegistrationCallback)?.Invoke(Descriptor); var element = (Snippet)_shape.Element; - if(element != null) - return element.Data.Get(Descriptor.Name); - - return null; + return element?.Data.Get(Descriptor.Name); } public string ToHtmlString() { diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Models/ElementInstance.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Models/ElementInstance.cs deleted file mode 100644 index 50a517ff95e..00000000000 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Models/ElementInstance.cs +++ /dev/null @@ -1,24 +0,0 @@ -//using System.Collections.Generic; -//using Orchard.Layouts.Framework.Elements; - -//namespace Orchard.Layouts.Models { -// public class ElementInstance { - -// public ElementInstance(string id, ElementDescriptor elementDescriptor, int index = 0, IDictionary Data = null) { -// Id = id; -// ElementDescriptor = elementDescriptor; -// Data = Data ?? new Dictionary(); -// Children = new List(); -// Index = index; -// } - -// public string Id { get; set; } - -// public ElementDescriptor ElementDescriptor { get; set; } -// public ElementInstance Parent { get; set; } -// public IList Children { get; set; } -// public int Index { get; set; } -// public IDictionary Data { get; set; } -// public bool IsTemplated { get; set; } -// } -//} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Models/ElementSessionState.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Models/ElementSessionState.cs index 6fcff6c7fb3..a0cbd38caeb 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Models/ElementSessionState.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Models/ElementSessionState.cs @@ -1,8 +1,8 @@ using System; -namespace Orchard.Layouts.Models { - [Serializable] - public class ElementSessionState { +namespace Orchard.Layouts.Models { + [Serializable] + public class ElementSessionState { public string TypeName { get; set; } public string ElementData { get; set; } public string ElementEditorData { get; set; } diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Models/SnippetDescriptor.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Models/SnippetDescriptor.cs index 6a4c4332de5..002450239be 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Models/SnippetDescriptor.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Models/SnippetDescriptor.cs @@ -1,11 +1,19 @@ using System.Collections.Generic; +using Orchard.Localization; namespace Orchard.Layouts.Models { public class SnippetDescriptor { + public string Category { get; set; } + public LocalizedString Description { get; set; } + public LocalizedString DisplayName { get; set; } + public string ToolboxIcon { get; set; } + + public SnippetDescriptor() { Fields = new List(); } + public IList Fields { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Models/SnippetFieldDescriptor.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Models/SnippetFieldDescriptor.cs index 7c5353303c0..591b38ed291 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Models/SnippetFieldDescriptor.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Models/SnippetFieldDescriptor.cs @@ -6,5 +6,7 @@ public class SnippetFieldDescriptor { public string Name { get; set; } public LocalizedString DisplayName { get; set; } public LocalizedString Description { get; set; } + + public bool IsValid => !string.IsNullOrEmpty(Name); } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Module.txt b/src/Orchard.Web/Modules/Orchard.Layouts/Module.txt index 626a1a950e8..7a42cf991a1 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Category: Layout Description: Provides tools to create layouts. Features: @@ -29,7 +29,7 @@ Features: Dependencies: Orchard.Layouts, Orchard.Projections Orchard.Layouts.Tokens: Name: Element Tokens - Description: Provides an element token provider that enables elements to be rendered using a token and enables tokens to be used inside of various elements such as Html, Text and Paragraph. + Description: Provides an element token provider that enables elements to be rendered using a token. Category: Layout Dependencies: Orchard.Layouts, Orchard.Tokens Orchard.Layouts.UI: diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj b/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj index 0f3d26d58c8..e207903e8a2 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj @@ -12,8 +12,8 @@ Properties Orchard.Layouts Orchard.Layouts - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -25,6 +25,9 @@ + + + true @@ -48,67 +51,54 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - - ..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True + + ..\..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll 3.5 - - - ..\..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll - True + + ..\..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.7\lib\net45\System.Net.Http.Formatting.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll - True + + ..\..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.7\lib\net45\System.Web.Http.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll - - ..\..\..\packages\YamlDotNet.3.8.0\lib\net35\YamlDotNet.dll - True - - - ..\..\..\packages\YamlDotNet.Dynamic.3.2.3\lib\net40\YamlDotNet.Dynamic.dll - True + + ..\..\..\packages\YamlDotNet.11.1.1\lib\net45\YamlDotNet.dll @@ -263,10 +253,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core + $(MvcBuildViews) {3158c928-888c-4a84-8bc1-4a8257489538} @@ -327,7 +319,6 @@ - @@ -360,6 +351,7 @@ + @@ -382,9 +374,6 @@ - - - @@ -493,7 +482,6 @@ - @@ -591,7 +579,7 @@ - + 10.0 @@ -617,7 +605,7 @@ --> - + @@ -631,7 +619,7 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Properties/AssemblyInfo.cs index d0e348a1e70..010117d5c30 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Properties/AssemblyInfo.cs @@ -32,6 +32,6 @@ // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Providers/BlueprintElementHarvester.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Providers/BlueprintElementHarvester.cs index 3ca89574b24..493d92089e1 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Providers/BlueprintElementHarvester.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Providers/BlueprintElementHarvester.cs @@ -13,7 +13,6 @@ namespace Orchard.Layouts.Providers { public class BlueprintElementHarvester : Component, IElementHarvester { private readonly Work _elementBlueprintService; private readonly Work _elementManager; - private bool _isHarvesting; public BlueprintElementHarvester(Work elementBlueprintService, Work elementManager) { _elementBlueprintService = elementBlueprintService; @@ -21,15 +20,14 @@ public BlueprintElementHarvester(Work elementBlueprint } public IEnumerable HarvestElements(HarvestElementsContext context) { - if (_isHarvesting) + if (context.IsHarvesting) return Enumerable.Empty(); - _isHarvesting = true; var blueprints = _elementBlueprintService.Value.GetBlueprints().ToArray(); var query = from blueprint in blueprints - let describeContext = new DescribeElementsContext {Content = context.Content, CacheVaryParam = "Blueprints"} + let describeContext = new DescribeElementsContext {Content = context.Content, CacheVaryParam = "Blueprints", IsHarvesting = true } let baseElementDescriptor = _elementManager.Value.GetElementDescriptorByTypeName(describeContext, blueprint.BaseElementTypeName) let baseElement = _elementManager.Value.ActivateElement(baseElementDescriptor) select new ElementDescriptor( @@ -48,9 +46,7 @@ from blueprint in blueprints } }; - var descriptors = query.ToArray(); - _isHarvesting = false; - return descriptors; + return query.ToArray(); } private static string GetCategory(ElementBlueprint blueprint) { @@ -68,6 +64,10 @@ private void Displaying(ElementDisplayingContext context, Element element) { foreach (var driver in drivers) { driver.Displaying(context); } + + if (element.Descriptor.Displaying != null) { + element.Descriptor.Displaying(context); + } } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Providers/ContentFieldElementHarvester.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Providers/ContentFieldElementHarvester.cs index 341a5f409e3..1ab4e6b3927 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Providers/ContentFieldElementHarvester.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Providers/ContentFieldElementHarvester.cs @@ -11,6 +11,7 @@ using Orchard.Layouts.Framework.Harvesters; using Orchard.Layouts.Helpers; using Orchard.Layouts.Services; +using Orchard.Mvc.Html; namespace Orchard.Layouts.Providers { public class ContentFieldElementHarvester : Component, IElementHarvester { @@ -44,7 +45,7 @@ public IEnumerable HarvestElements(HarvestElementsContext con var field = tuple.Item2; var name = String.Format("{0}.{1}", part.Name, field.Name); var displayName = field.DisplayName; - yield return new ElementDescriptor(elementType, name, T(displayName), T(field.DisplayName), contentFieldElement.Category) { + yield return new ElementDescriptor(elementType, name, T.Encode(displayName), T.Encode(field.DisplayName), contentFieldElement.Category) { Displaying = displayContext => Displaying(displayContext), ToolboxIcon = "\uf1b2" }; diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Providers/ContentPartElementHarvester.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Providers/ContentPartElementHarvester.cs index 2977ab3982e..24841bf032f 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Providers/ContentPartElementHarvester.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Providers/ContentPartElementHarvester.cs @@ -10,6 +10,7 @@ using Orchard.Layouts.Framework.Harvesters; using Orchard.Layouts.Services; using Orchard.Layouts.Settings; +using Orchard.Mvc.Html; using Orchard.Utility.Extensions; namespace Orchard.Layouts.Providers { @@ -37,8 +38,8 @@ public IEnumerable HarvestElements(HarvestElementsContext con var partSettings = contentPart.Settings.TryGetModel(); var partDescription = partSettings != null ? partSettings.Description : null; - var description = T(!String.IsNullOrWhiteSpace(partDescription) ? partDescription : contentPart.Name); - return new ElementDescriptor(elementType, contentPart.Name, T(contentPart.Name.CamelFriendly()), description, contentPartElement.Category) { + var description = T.Encode(!String.IsNullOrWhiteSpace(partDescription) ? partDescription : contentPart.Name); + return new ElementDescriptor(elementType, contentPart.Name, T.Encode(contentPart.Name.CamelFriendly()), description, contentPartElement.Category) { Displaying = displayContext => Displaying(displayContext), ToolboxIcon = "\uf1b2", StateBag = new Dictionary { diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Providers/PlaceableContentElementHarvester.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Providers/PlaceableContentElementHarvester.cs index 3a7d37ab8a9..f0bb8b44862 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Providers/PlaceableContentElementHarvester.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Providers/PlaceableContentElementHarvester.cs @@ -14,6 +14,7 @@ using Orchard.Layouts.Helpers; using Orchard.Layouts.Settings; using Orchard.Layouts.ViewModels; +using Orchard.Mvc.Html; using ContentItem = Orchard.ContentManagement.ContentItem; namespace Orchard.Layouts.Providers { @@ -30,7 +31,7 @@ public IEnumerable HarvestElements(HarvestElementsContext con return contentTypeDefinitions.Select(contentTypeDefinition => { var settings = contentTypeDefinition.Settings; var description = settings.ContainsKey("Description") ? settings["Description"] : contentTypeDefinition.DisplayName; - return new ElementDescriptor(typeof (PlaceableContentItem), contentTypeDefinition.Name, T(contentTypeDefinition.DisplayName), T(description), category: "Content Items") { + return new ElementDescriptor(typeof (PlaceableContentItem), contentTypeDefinition.Name, T.Encode(contentTypeDefinition.DisplayName), T.Encode(description), category: "Content Items") { Displaying = Displaying, Editor = Editor, UpdateEditor = UpdateEditor, diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Providers/SnippetElementHarvester.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Providers/SnippetElementHarvester.cs index cca37506fa3..067ffc566d1 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Providers/SnippetElementHarvester.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Providers/SnippetElementHarvester.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text.RegularExpressions; using Orchard.DisplayManagement; using Orchard.DisplayManagement.Descriptors; using Orchard.Environment; @@ -14,6 +13,7 @@ using Orchard.Layouts.Framework.Harvesters; using Orchard.Layouts.Helpers; using Orchard.Layouts.Models; +using Orchard.Layouts.Serialization; using Orchard.Layouts.Services; using Orchard.Layouts.Shapes; using Orchard.Layouts.ViewModels; @@ -21,7 +21,7 @@ using Orchard.Themes.Services; using Orchard.Tokens; using Orchard.Utility.Extensions; -using YamlDotNet.Dynamic; +using YamlDotNet.Serialization; namespace Orchard.Layouts.Providers { [OrchardFeature("Orchard.Layouts.Snippets")] @@ -36,6 +36,9 @@ public class SnippetElementHarvester : IElementHarvester { private readonly Work _tokenizer; private readonly IWorkContextAccessor _wca; + public Localizer T; + + public SnippetElementHarvester( IWorkContextAccessor workContextAccessor, Work shapeFactory, @@ -54,30 +57,31 @@ public SnippetElementHarvester( _tokenizer = tokenizer; _currentThemeShapeBindingResolver = currentThemeShapeBindingResolver; _wca = workContextAccessor; + + T = NullLocalizer.Instance; } + public IEnumerable HarvestElements(HarvestElementsContext context) { var currentThemeName = _siteThemeService.Value.GetCurrentThemeName(); var shapeTable = _shapeTableLocator.Value.Lookup(currentThemeName); - var shapeDescriptors = shapeTable.Bindings.Where(x => !String.Equals(x.Key, "Elements_Snippet", StringComparison.OrdinalIgnoreCase) && x.Key.EndsWith(SnippetShapeSuffix, StringComparison.OrdinalIgnoreCase)).ToDictionary(x => x.Key, x => x.Value.ShapeDescriptor); + var shapeDescriptors = shapeTable.Bindings + .Where(x => !string.Equals(x.Key, "Elements_Snippet", StringComparison.OrdinalIgnoreCase) && + x.Key.EndsWith(SnippetShapeSuffix, StringComparison.OrdinalIgnoreCase)) + .ToDictionary(x => x.Key, x => x.Value.ShapeDescriptor); var elementType = typeof(Snippet); var snippetElement = (Snippet)_elementFactory.Value.Activate(elementType); foreach (var shapeDescriptor in shapeDescriptors) { - var snippetManifest = ParseSnippetManifest(shapeDescriptor.Value.BindingSource); + var snippetDescriptor = CreateSnippetDescriptor(shapeDescriptor.Value, snippetElement); var shapeType = shapeDescriptor.Value.ShapeType; - var elementName = GetDisplayName(snippetManifest, shapeDescriptor.Value.BindingSource); - var toolboxIcon = GetToolboxIcon(snippetManifest, snippetElement); - var description = GetDescription(snippetManifest, shapeType); - var category = GetCategory(snippetManifest, snippetElement); - var closureDescriptor = shapeDescriptor; - var snippetDescriptor = ParseSnippetDescriptor(snippetManifest); - yield return new ElementDescriptor(elementType, shapeType, new LocalizedString(elementName), description, category) { - Displaying = displayContext => Displaying(displayContext, closureDescriptor.Value, snippetDescriptor), - ToolboxIcon = toolboxIcon, - EnableEditorDialog = snippetDescriptor != null || HasSnippetFields(shapeDescriptor.Value), - Editor = ctx => Editor(snippetDescriptor ?? DescribeSnippet(shapeType, snippetElement), ctx), - UpdateEditor = ctx => UpdateEditor(snippetDescriptor ?? DescribeSnippet(shapeType, snippetElement), ctx) + + yield return new ElementDescriptor(elementType, shapeType, snippetDescriptor.DisplayName, snippetDescriptor.Description, snippetDescriptor.Category) { + Displaying = displayContext => Displaying(displayContext, shapeDescriptor.Value, snippetDescriptor), + ToolboxIcon = snippetDescriptor.ToolboxIcon, + EnableEditorDialog = snippetDescriptor.Fields.Any(), + Editor = ctx => Editor(snippetDescriptor, ctx), + UpdateEditor = ctx => UpdateEditor(snippetDescriptor, ctx) }; } } @@ -104,7 +108,7 @@ private void UpdateEditor(SnippetDescriptor descriptor, ElementEditorContext con } viewModel.FieldEditors = descriptor.Fields.Select(x => { - var fieldEditorTemplateName = String.Format("Elements.Snippet.Field.{0}", x.Type ?? "Text"); + var fieldEditorTemplateName = $"Elements.Snippet.Field.{x.Type ?? "Text"}"; var fieldDescriptorViewModel = new SnippetFieldViewModel { Descriptor = x, Value = context.Element.Data.Get(x.Name) @@ -125,6 +129,7 @@ private void Displaying(ElementDisplayingContext context, ShapeDescriptor shapeD var shape = (dynamic)_shapeFactory.Value.Create(shapeType); shape.Element = context.Element; + shape.SnippetDescriptor = snippetDescriptor; if (snippetDescriptor != null) { foreach (var fieldDescriptor in snippetDescriptor.Fields) { @@ -137,113 +142,67 @@ private void Displaying(ElementDisplayingContext context, ShapeDescriptor shapeD context.ElementShape.Snippet = shape; } - private dynamic ParseSnippetManifest(string bindingSource) { - var physicalSourcePath = _wca.GetContext().HttpContext.Server.MapPath(bindingSource); - var paramsFileName = Path.Combine(Path.GetDirectoryName(physicalSourcePath) ?? "", Path.GetFileNameWithoutExtension(physicalSourcePath) + ".txt"); - - if (!File.Exists(paramsFileName)) - return null; - - var yaml = File.ReadAllText(paramsFileName); - var snippetConfig = Deserialize(yaml); - - return snippetConfig; - } - - private string GetDisplayName(dynamic snippetManifest, string bindingSource) { - if (snippetManifest != null && (string)snippetManifest.DisplayName != null) { - return (string)snippetManifest.DisplayName; + private SnippetDescriptor CreateSnippetDescriptor(ShapeDescriptor shapeDescriptor, Snippet snippetElement) { + // Initializing and checking access to the Snippet manifest file. + var physicalSourcePath = _wca.GetContext().HttpContext.Server.MapPath(shapeDescriptor.BindingSource); + var fullPath = Path.Combine( + Path.GetDirectoryName(physicalSourcePath) ?? "", + Path.GetFileNameWithoutExtension(physicalSourcePath) + ".txt"); + + SnippetDescriptor descriptor; + // Reading and parsing the manifest if it exists. + if (File.Exists(fullPath)) { + var deserializer = new DeserializerBuilder() + .IgnoreUnmatchedProperties() + .WithTypeConverter(new LocalizedStringYamlConverter()) + .Build(); + + descriptor = deserializer.Deserialize(File.OpenText(fullPath)); } + // Otherwise extract the Fields from the Snippet shape template. + else { + var shape = (dynamic)_shapeFactory.Value.Create(shapeDescriptor.ShapeType); + shape.Element = snippetElement; - var fileName = Path.GetFileNameWithoutExtension(bindingSource) ?? ""; - var lastIndex = fileName.IndexOf(SnippetShapeSuffix, StringComparison.OrdinalIgnoreCase); - return fileName.Substring(0, lastIndex).CamelFriendly(); - } + descriptor = new SnippetDescriptor(); - private string GetToolboxIcon(dynamic snippetManifest, Snippet snippetElement) { - if (snippetManifest != null && (string)snippetManifest.ToolboxIcon != null) { - return Regex.Unescape((string)snippetManifest.ToolboxIcon); - } + shape.DescriptorRegistrationCallback = (Action)(fieldDescriptor => { + // Not using Dictionary, as that will break rendering the view for some obscure reason. + var existingFieldDescriptor = descriptor.Fields.SingleOrDefault(field => field.Name == fieldDescriptor.Name); - return snippetElement.ToolboxIcon; - } + if (existingFieldDescriptor == null) + descriptor.Fields.Add(fieldDescriptor); - private LocalizedString GetDescription(dynamic snippetManifest, string shapeType) { - if (snippetManifest != null && (string)snippetManifest.Description != null) { - return new LocalizedString((string)snippetManifest.Description); - } + if (fieldDescriptor.DisplayName == null) + fieldDescriptor.DisplayName = new LocalizedString(fieldDescriptor.Name); + }); - return new LocalizedString(String.Format("An element that renders the {0} shape.", shapeType)); - } + using (_currentThemeShapeBindingResolver.Value.Enable()) { + _shapeDisplay.Value.Display(shape); + } - private string GetCategory(dynamic snippetManifest, Snippet snippetElement) { - if (snippetManifest != null && (string)snippetManifest.Category != null) { - return (string)snippetManifest.Category; + shape.SnippetDescriptor = descriptor; } - return snippetElement.Category; - } - - private SnippetDescriptor ParseSnippetDescriptor(dynamic snippetManifest) { - if(snippetManifest == null || snippetManifest.Fields.Count == 0) { - return null; - } + // Checking the validity of the parsed values, include those of the Snippet's Fields. + if (string.IsNullOrEmpty(descriptor.Category)) + descriptor.Category = snippetElement.Category; - var fieldsConfig = snippetManifest.Fields.Children; - var descriptor = new SnippetDescriptor(); + if (string.IsNullOrEmpty(descriptor.Description?.Text)) + descriptor.Description = T("An element that renders the {0} shape.", shapeDescriptor.ShapeType); - foreach (var fieldConfig in fieldsConfig) { - descriptor.Fields.Add(new SnippetFieldDescriptor { - Name = (string)fieldConfig.Name, - Type = (string)fieldConfig.Type, - DisplayName = new LocalizedString((string)fieldConfig.DisplayName), - Description = new LocalizedString((string)fieldConfig.Description) - }); + if (string.IsNullOrEmpty(descriptor.DisplayName?.Text)) { + var fileName = Path.GetFileNameWithoutExtension(shapeDescriptor.BindingSource) ?? ""; + var lastIndex = fileName.IndexOf(SnippetShapeSuffix, StringComparison.OrdinalIgnoreCase); + descriptor.DisplayName = T(fileName.Substring(0, lastIndex).CamelFriendly()); } - return descriptor; - } - - private SnippetDescriptor DescribeSnippet(string shapeType, Snippet element) { - var shape = (dynamic)_shapeFactory.Value.Create(shapeType); - shape.Element = element; - return DescribeSnippet(shape); - } - - private SnippetDescriptor DescribeSnippet(dynamic shape) { - // Execute the shape and intercept calls to the Html.SnippetField method. - var descriptor = new SnippetDescriptor(); - shape.DescriptorRegistrationCallback = (Action)(fieldDescriptor => { - var existingDescriptor = descriptor.Fields.SingleOrDefault(x => x.Name == fieldDescriptor.Name); // Not using Dictionary, as that will break rendering the view for some obscure reason. + if (string.IsNullOrEmpty(descriptor.ToolboxIcon)) + descriptor.ToolboxIcon = snippetElement.ToolboxIcon; - if (existingDescriptor == null) - descriptor.Fields.Add(fieldDescriptor); + descriptor.Fields = descriptor.Fields.Where(field => field.IsValid).ToList(); - if (fieldDescriptor.DisplayName == null) - fieldDescriptor.DisplayName = new LocalizedString(fieldDescriptor.Name); - }); - - using (_currentThemeShapeBindingResolver.Value.Enable()) { - _shapeDisplay.Value.Display(shape); - } - - shape.SnippetDescriptor = descriptor; return descriptor; } - - private bool HasSnippetFields(ShapeDescriptor shapeDescriptor) { - var bindingSource = shapeDescriptor.BindingSource; - var localFileName = _wca.GetContext().HttpContext.Server.MapPath(bindingSource); - - if (!File.Exists(localFileName)) - return false; - - var markup = File.ReadAllText(localFileName); - return markup.Contains("@Html.SnippetField"); - } - - private dynamic Deserialize(string yaml) { - return new DynamicYaml(yaml); - } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Routes.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Routes.cs index 4f71042fb1a..9d6e7934dec 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Routes.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Routes.cs @@ -6,13 +6,7 @@ namespace Orchard.Layouts { public class Routes : IRouteProvider { public void GetRoutes(ICollection routes) { - foreach (var route in GetRoutes()) { - routes.Add(route); - } - } - - public IEnumerable GetRoutes() { - yield return new RouteDescriptor { + var routeDescriptor = new RouteDescriptor { Route = new Route( "Admin/Layouts/{controller}/{action}/{id}", new RouteValueDictionary { @@ -25,6 +19,8 @@ public IEnumerable GetRoutes() { }, new MvcRouteHandler()) }; + + routes.Add(routeDescriptor); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutDesignerHost.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutDesignerHost.js index 4e7fa00e4f7..d516361e1d2 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutDesignerHost.js +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutDesignerHost.js @@ -4,6 +4,13 @@ this.element = element; this.element.data("layout-designer-host", this); this.editor = layoutEditor; + + function serializelayoutHandler() { + serializeLayout(); + }; + + $(document).on("serializelayout", serializelayoutHandler); + this.settings = { antiForgeryToken: self.element.data("anti-forgery-token"), editorDialogTitleFormat: self.element.data("editor-dialog-title-format"), @@ -20,6 +27,16 @@ } }; + this.addElement = function (contentType) { + var deferred = new $.Deferred(); + deferred.resolve(); + $.event.trigger({ + type: "layouteditor:edited" + }); + + return deferred.promise(); + }; + this.editElement = function (element) { var deferred = new $.Deferred(); @@ -38,11 +55,14 @@ }, "post"); dialog.element.on("command", function (e, args) { - - switch(args.command) { + + switch (args.command) { case "update": deferred.resolve(args); dialog.close(); + $.event.trigger({ + type: "layouteditor:edited" + }); break; case "cancel": case "close": @@ -98,7 +118,7 @@ var layoutDataDataJson = serializeCanvas(); var recycleBinDataJson = serializeRecycleBin(); - layoutDataField.val(layoutDataDataJson); + layoutDataField.val(layoutDataDataJson).trigger("change"); recycleBinDataField.val(recycleBinDataJson); }; diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.js index 91315fc60d2..493dad5cf56 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.js +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.js @@ -182,10 +182,13 @@ angular }); $scope["delete"] = function (element) { element["delete"](); + $.event.trigger({ + type: "layouteditor:edited" + }); }; if ($scope.element.hasEditor) { $scope.edit = function () { - $scope.$root.editElement($scope.element).then(function (args) { + $scope.$root.editElement($scope.element).done(function (args) { $scope.$apply(function () { if (args.cancel) return; @@ -281,7 +284,7 @@ angular receivedElement.setEditor(element.editor); receivedElement.setParent(element); if (!!receivedElement.hasEditor) { - $scope.$root.editElement(receivedElement).then(function (args) { + $scope.$root.editElement(receivedElement).done(function (args) { if (!args.cancel) { receivedElement.data = args.element.data; receivedElement.applyElementEditorModel(args.elementEditorModel); @@ -305,6 +308,9 @@ angular element.setIsDropTarget(false); if (!!receivedElement) receivedElement.setIsFocused(); + $scope.$root.addElement(receivedElement).done(function () { + return; + }); }); }); } @@ -441,6 +447,9 @@ angular break; case "paste": focusedElement.paste(e.originalEvent.clipboardData); + $.event.trigger({ + type: "layouteditor:edited" + }); break; } }); @@ -816,6 +825,8 @@ angular connectWith: _(parentClasses).map(function (e) { return "#" + editorId + " " + e + ":not(.layout-container-sealed) > .layout-element-wrapper > .layout-children"; }).join(", "), placeholder: placeholderClasses, "ui-floating": floating, + helper: "clone", + appendTo: "body", create: function (e, ui) { e.target.isToolbox = true; // Will indicate to connected sortables that dropped items were sent from toolbox. }, @@ -848,29 +859,7 @@ angular } ], templateUrl: environment.templateUrl("Toolbox"), - replace: true, - link: function (scope, element) { - var toolbox = element.find(".layout-toolbox"); - $(window).on("resize scroll", function (e) { - var canvas = element.parent().find(".layout-canvas"); - // If the canvas is taller than the toolbox, make the toolbox sticky-positioned within the editor - // to help the user avoid excessive vertical scrolling. - var canvasIsTaller = !!canvas && canvas.height() > toolbox.height(); - var windowPos = $(window).scrollTop(); - if (canvasIsTaller && windowPos > element.offset().top + element.height() - toolbox.height()) { - toolbox.addClass("sticky-bottom"); - toolbox.removeClass("sticky-top"); - } - else if (canvasIsTaller && windowPos > element.offset().top) { - toolbox.addClass("sticky-top"); - toolbox.removeClass("sticky-bottom"); - } - else { - toolbox.removeClass("sticky-top"); - toolbox.removeClass("sticky-bottom"); - } - }); - } + replace: true }; } ]); @@ -899,4 +888,4 @@ angular } ]); -//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L0xheW91dEVkaXRvci9Nb2R1bGUuanMiLCJPcmNoYXJkLldlYi9Nb2R1bGVzL09yY2hhcmQuTGF5b3V0cy9Bc3NldHMvSmF2YVNjcmlwdC9MYXlvdXRFZGl0b3IvU2VydmljZXMvQ2xpcGJvYXJkLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTGF5b3V0RWRpdG9yL1NlcnZpY2VzL1Njb3BlQ29uZmlndXJhdG9yLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTGF5b3V0RWRpdG9yL0RpcmVjdGl2ZXMvRWRpdG9yLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTGF5b3V0RWRpdG9yL0RpcmVjdGl2ZXMvQ2FudmFzLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTGF5b3V0RWRpdG9yL0RpcmVjdGl2ZXMvQ2hpbGQuanMiLCJPcmNoYXJkLldlYi9Nb2R1bGVzL09yY2hhcmQuTGF5b3V0cy9Bc3NldHMvSmF2YVNjcmlwdC9MYXlvdXRFZGl0b3IvRGlyZWN0aXZlcy9Db2x1bW4uanMiLCJPcmNoYXJkLldlYi9Nb2R1bGVzL09yY2hhcmQuTGF5b3V0cy9Bc3NldHMvSmF2YVNjcmlwdC9MYXlvdXRFZGl0b3IvRGlyZWN0aXZlcy9Db250ZW50LmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTGF5b3V0RWRpdG9yL0RpcmVjdGl2ZXMvR3JpZC5qcyIsIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L0xheW91dEVkaXRvci9EaXJlY3RpdmVzL1Jvdy5qcyIsIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L0xheW91dEVkaXRvci9EaXJlY3RpdmVzL1BvcHVwLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTGF5b3V0RWRpdG9yL0RpcmVjdGl2ZXMvVG9vbGJveC5qcyIsIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L0xheW91dEVkaXRvci9EaXJlY3RpdmVzL1Rvb2xib3hHcm91cC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLE9BQU8sQ0FBQyxNQUFNLENBQUMsY0FBYyxFQUFFLENBQUMsWUFBWSxFQUFFLFlBQVksRUFBRSxhQUFhLENBQUMsQ0FBQyxDQUFDO0FDQTVFLElBQUksWUFBWSxDQUFDO0FBQ2pCLENBQUMsVUFBUyxZQUFZO0lBRWxCLElBQUksU0FBUyxHQUFHO1FBQ1osSUFBSSxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2hCLElBQUksQ0FBQyxjQUFjLEdBQUcsRUFBRSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDO1FBQ3pCLElBQUksQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDO1FBRXpCLElBQUksQ0FBQyxPQUFPLEdBQUcsVUFBUyxXQUFXLEVBQUUsSUFBSTtZQUNyQyxJQUFJLENBQUMsY0FBYyxDQUFDLFdBQVcsQ0FBQyxHQUFHLElBQUksQ0FBQztZQUN4QyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztRQUM1QixDQUFDLENBQUM7UUFDRixJQUFJLENBQUMsT0FBTyxHQUFHLFVBQVUsV0FBVztZQUNoQyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztZQUN4QixNQUFNLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUM1QyxDQUFDLENBQUM7UUFDRixJQUFJ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QUUsVUFBVTtnQkFDN0IsVUFBVSxNQUFNLEVBQUUsUUFBUTtvQkFDdEIsSUFBSSxxQkFBcUIsR0FBRyx3QkFBd0IsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksR0FBRyxjQUFjLENBQUM7b0JBQzdGLE1BQU0sQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxLQUFLLE1BQU0sQ0FBQztvQkFDaEUsTUFBTSxDQUFDLGlCQUFpQixHQUFHLFVBQVUsQ0FBQzt3QkFDbEMsTUFBTSxDQUFDLFdBQVcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUM7d0JBQ3pDLENBQUMsQ0FBQyxNQUFNLENBQUMscUJBQXFCLEVBQUUsTUFBTSxDQUFDLFdBQVcsRUFBRSxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsdUNBQXVDO3dCQUM5RyxDQUFDLENBQUMsY0FBYyxFQUFFLENBQUM7d0JBQ25CLENBQUMsQ0FBQyxlQUFlLEVBQUUsQ0FBQztvQkFDeEIsQ0FBQyxDQUFDO2dCQUNOLENBQUM7YUFDSjtZQUNELFdBQVcsRUFBRSxXQUFXLENBQUMsV0FBVyxDQUFDLGNBQWMsQ0FBQztZQUNwRCxPQUFPLEVBQUUsSUFBSTtTQUNoQixDQUFDO0lBQ04sQ0FBQztDQUNKLENBQUMsQ0FBQyIsImZpbGUiOiJMYXlvdXRFZGl0b3IuanMiLCJzb3VyY2VzQ29udGVudCI6WyJhbmd1bGFyLm1vZHVsZShcIkxheW91dEVkaXRvclwiLCBbXCJuZ1Nhbml0aXplXCIsIFwibmdSZXNvdXJjZVwiLCBcInVpLnNvcnRhYmxlXCJdKTsiLCJ2YXIgTGF5b3V0RWRpdG9yO1xyXG4oZnVuY3Rpb24oTGF5b3V0RWRpdG9yKSB7XHJcblxyXG4gICAgdmFyIENsaXBib2FyZCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XHJcbiAgICAgICAgdGhpcy5fY2xpcGJvYXJkRGF0YSA9IHt9O1xyXG4gICAgICAgIHRoaXMuX2lzRGlzYWJsZWQgPSBmYWxzZTtcclxuICAgICAgICB0aGlzLl93YXNJbnZva2VkID0gZmFsc2U7XHJcblxyXG4gICAgICAgIHRoaXMuc2V0RGF0YSA9IGZ1bmN0aW9uKGNvbnRlbnRUeXBlLCBkYXRhKSB7XHJcbiAgICAgICAgICAgIHNlbGYuX2NsaXBib2FyZERhdGFbY29udGVudFR5cGVdID0gZGF0YTtcclxuICAgICAgICAgICAgc2VsZi5fd2FzSW52b2tlZCA9IHRydWU7XHJcbiAgICAgICAgfTtcclxuICAgICAgICB0aGlzLmdldERhdGEgPSBmdW5jdGlvbiAoY29udGVudFR5cGUpIHtcclxuICAgICAgICAgICAgc2VsZi5fd2FzSW52b2tlZCA9IHRydWU7XHJcbiAgICAgICAgICAgIHJldHVybiBzZWxmLl9jbGlwYm9hcmREYXRhW2NvbnRlbnRUeXBlXTtcclxuICAgICAgICB9O1xyXG4gICAgICAgIHRoaXMuZGlzYWJsZSA9IGZ1bmN0aW9uKCkge1xyXG4gICAgICAgICAgICBzZWxmLl9pc0Rpc2FibGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgc2VsZi5fd2FzSW52b2tlZCA9IGZhbHNlO1xyXG4gICAgICAgICAgICBzZWxmLl9jbGlwYm9hcmREYXRhID0ge307XHJcbiAgICAgICAgfTtcclxuICAgICAgICB0aGlzLmlzRGlzYWJsZWQgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBzZWxmLl9pc0Rpc2FibGVkO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLndhc0ludm9rZWQgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBzZWxmLl93YXNJbnZva2VkO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBMYXlvdXRFZGl0b3IuQ2xpcGJvYXJkID0gbmV3IENsaXBib2FyZCgpO1xyXG5cclxuICAgIGFuZ3VsYXJcclxuICAgICAgICAubW9kdWxlKFwiTGF5b3V0RWRpdG9yXCIpXHJcbiAgICAgICAgLmZhY3RvcnkoXCJjbGlwYm9hcmRcIiwgW1xyXG4gICAgICAgICAgICBmdW5jdGlvbigpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICAgICAgc2V0RGF0YTogTGF5b3V0RWRpdG9yLkNsaXBib2FyZC5zZXREYXRhLFxyXG4gICAgICAgICAgICAgICAgICAgIGdldERhdGE6IExheW91dEVkaXRvci5DbGlwYm9hcmQuZ2V0RGF0YSxcclxuICAgICAgICAgICAgICAgICAgICBkaXNhYmxlOiBMYXlvdXRFZGl0b3IuQ2xpcGJvYXJkLmRpc2FibGUsXHJcbiAgICAgICAgICAgICAgICAgICAgaXNEaXNhYmxlZDogTGF5b3V0RWRpdG9yLkNsaXBib2FyZC5pc0Rpc2FibGVkLFxyXG4gICAgICAgICAgICAgICAgICAgIHdhc0ludm9rZWQ6IExheW91dEVkaXRvci5DbGlwYm9hcmQud2FzSW52b2tlZFxyXG4gICAgICAgICAgICAgICAgfTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIF0pO1xyXG59KShMYXlvdXRFZGl0b3IgfHwgKExheW91dEVkaXRvciA9IHt9KSk7IiwiYW5ndWxhclxyXG4gICAgLm1vZHVsZShcIkxheW91dEVkaXRvclwiKVxyXG4gICAgLmZhY3RvcnkoXCJzY29wZUNvbmZpZ3VyYXRvclwiLCBbXCIkdGltZW91dFwiLCBcImNsaXBib2FyZFwiLFxyXG4gICAgICAgIGZ1bmN0aW9uICgkdGltZW91dCwgY2xpcGJvYXJkKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB7XHJcblxyXG4gICAgICAgICAgICAgICAgY29uZmlndXJlRm9yRWxlbWVudDogZnVuY3Rpb24gKCRzY29wZSwgJGVsZW1lbnQpIHtcclxuICAgICAgICAgICAgICAgIFxyXG4gICAgICAgICAgICAgICAgICAgICRlbGVtZW50LmZpbmQoXCIubGF5b3V0LXBhbmVsXCIpLmNsaWNrKGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICRlbGVtZW50LnBhcmVudCgpLmtleWRvd24oZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGhhbmRsZWQgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlc2V0Rm9jdXMgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGVsZW1lbnQgPSAkc2NvcGUuZWxlbWVudDtcclxuICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVsZW1lbnQuZWRpdG9yLmlzRHJhZ2dpbmcpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiBuYXRpdmUgY2xpcGJvYXJkIHN1cHBvcnQgZXhpc3RzLCB0aGUgcHNldWRvLWNsaXBib2FyZCB3aWxsIGhhdmUgYmVlbiBkaXNhYmxlZC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFjbGlwYm9hcmQuaXNEaXNhYmxlZCgpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgZm9jdXNlZEVsZW1lbnQgPSBlbGVtZW50LmVkaXRvci5mb2N1c2VkRWxlbWVudDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghIWZvY3VzZWRFbGVtZW50KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUHNldWRvIGNsaXBib2FyZCBoYW5kbGluZyBmb3IgYnJvd3NlcnMgbm90IGFsbG93aW5nIHJlYWwgY2xpcGJvYXJkIG9wZXJhdGlvbnMuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGUuY3RybEtleSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKGUud2hpY2gpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSA2NzogLy8gQ1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9jdXNlZEVsZW1lbnQuY29weShjbGlwYm9hcmQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgODg6IC8vIFhcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvY3VzZWRFbGVtZW50LmN1dChjbGlwYm9hcmQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgODY6IC8vIFZcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvY3VzZWRFbGVtZW50LnBhc3RlKGNsaXBib2FyZCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFlLmN0cmxLZXkgJiYgIWUuc2hpZnRLZXkgJiYgIWUuYWx0S2V5ICYmIGUud2hpY2ggPT0gNDYpIHsgLy8gRGVsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZGVsZXRlKGVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoIWUuY3RybEtleSAmJiAhZS5zaGlmdEtleSAmJiAhZS5hbHRLZXkgJiYgKGUud2hpY2ggPT0gMzIgfHwgZS53aGljaCA9PSAyNykpIHsgLy8gU3BhY2Ugb3IgRXNjXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkZWxlbWVudC5maW5kKFwiLmxheW91dC1wYW5lbC1hY3Rpb24tcHJvcGVydGllc1wiKS5maXJzdCgpLmNsaWNrKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYW5kbGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEhZWxlbWVudC5oYXNFZGl0b3IpIHsgLy8gVGhpcyBlbGVtZW50IGhhcyBhbiBlZGl0b3IgZGlhbG9nLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFlLmN0cmxLZXkgJiYgIWUuc2hpZnRLZXkgJiYgIWUuYWx0S2V5ICYmIGUud2hpY2ggPT0gMTMpIHsgLy8gRW50ZXJcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkZWxlbWVudC5maW5kKFwiLmxheW91dC1wYW5lbC1hY3Rpb24tZWRpdFwiKS5maXJzdCgpLmNsaWNrKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghIWVsZW1lbnQuY2hpbGRyZW4pIHsgLy8gVGhpcyBpcyBhIGNvbnRhaW5lci5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghZS5jdHJsS2V5ICYmICFlLnNoaWZ0S2V5ICYmIGUuYWx0S2V5ICYmIGUud2hpY2ggPT0gNDApIHsgLy8gQWx0K0Rvd25cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZWxlbWVudC5jaGlsZHJlbi5sZW5ndGggPiAwKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LmNoaWxkcmVuWzBdLnNldElzRm9jdXNlZCgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50LnR5cGUgPT0gXCJDb2x1bW5cIikgeyAvLyBUaGlzIGlzIGEgY29sdW1uLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBjb25uZWN0QWRqYWNlbnQgPSAhZS5jdHJsS2V5O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlLndoaWNoID09IDM3KSB7IC8vIExlZnRcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGUuYWx0S2V5KVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5leHBhbmRMZWZ0KGNvbm5lY3RBZGphY2VudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlLnNoaWZ0S2V5KVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5jb250cmFjdFJpZ2h0KGNvbm5lY3RBZGphY2VudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoZS53aGljaCA9PSAzOSkgeyAvLyBSaWdodFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZS5hbHRLZXkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LmNvbnRyYWN0TGVmdChjb25uZWN0QWRqYWNlbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZS5zaGlmdEtleSlcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuZXhwYW5kUmlnaHQoY29ubmVjdEFkamFjZW50KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoISFlbGVtZW50LnBhcmVudCkgeyAvLyBUaGlzIGlzIGEgY2hpbGQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZS5hbHRLZXkgJiYgZS53aGljaCA9PSAzOCkgeyAvLyBBbHQrVXBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LnBhcmVudC5zZXRJc0ZvY3VzZWQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYW5kbGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZWxlbWVudC5wYXJlbnQudHlwZSA9PSBcIlJvd1wiKSB7IC8vIFBhcmVudCBpcyBhIGhvcml6b250YWwgY29udGFpbmVyLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghZS5jdHJsS2V5ICYmICFlLnNoaWZ0S2V5ICYmICFlLmFsdEtleSAmJiBlLndoaWNoID09IDM3KSB7IC8vIExlZnRcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5wYXJlbnQubW92ZUZvY3VzUHJldkNoaWxkKGVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYW5kbGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoIWUuY3RybEtleSAmJiAhZS5zaGlmdEtleSAmJiAhZS5hbHRLZXkgJiYgZS53aGljaCA9PSAzOSkgeyAvLyBSaWdodFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LnBhcmVudC5tb3ZlRm9jdXNOZXh0Q2hpbGQoZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChlLmN0cmxLZXkgJiYgIWUuc2hpZnRLZXkgJiYgIWUuYWx0S2V5ICYmIGUud2hpY2ggPT0gMzcpIHsgLy8gQ3RybCtMZWZ0XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQubW92ZVVwKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc2V0Rm9jdXMgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYW5kbGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoZS5jdHJsS2V5ICYmICFlLnNoaWZ0S2V5ICYmICFlLmFsdEtleSAmJiBlLndoaWNoID09IDM5KSB7IC8vIEN0cmwrUmlnaHRcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5tb3ZlRG93bigpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYW5kbGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHsgLy8gUGFyZW50IGlzIGEgdmVydGljYWwgY29udGFpbmVyLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghZS5jdHJsS2V5ICYmICFlLnNoaWZ0S2V5ICYmICFlLmFsdEtleSAmJiBlLndoaWNoID09IDM4KSB7IC8vIFVwXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQucGFyZW50Lm1vdmVGb2N1c1ByZXZDaGlsZChlbGVtZW50KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKCFlLmN0cmxLZXkgJiYgIWUuc2hpZnRLZXkgJiYgIWUuYWx0S2V5ICYmIGUud2hpY2ggPT0gNDApIHsgLy8gRG93blxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LnBhcmVudC5tb3ZlRm9jdXNOZXh0Q2hpbGQoZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChlLmN0cmxLZXkgJiYgIWUuc2hpZnRLZXkgJiYgIWUuYWx0S2V5ICYmIGUud2hpY2ggPT0gMzgpIHsgLy8gQ3RybCtVcFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50Lm1vdmVVcCgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNldEZvY3VzID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKGUuY3RybEtleSAmJiAhZS5zaGlmdEtleSAmJiAhZS5hbHRLZXkgJiYgZS53aGljaCA9PSA0MCkgeyAvLyBDdHJsK0Rvd25cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5tb3ZlRG93bigpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYW5kbGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChoYW5kbGVkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuJGFwcGx5KCk7IC8vIEV2ZW50IGlzIG5vdCB0cmlnZ2VyZWQgYnkgQW5ndWxhciBkaXJlY3RpdmUgYnV0IHJhdyBldmVudCBoYW5kbGVyIG9uIGVsZW1lbnQuXHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBIQUNLOiBXb3JrYXJvdW5kIGJlY2F1c2Ugb2YgaG93IEFuZ3VsYXIgdHJlYXRzIHRoZSBET00gd2hlbiBlbGVtZW50cyBhcmUgc2hpZnRlZCBhcm91bmQgLSBpbnB1dCBmb2N1cyBpcyBzb21ldGltZXMgbG9zdC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJlc2V0Rm9jdXMpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuJGFwcGx5KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5lZGl0b3IuZm9jdXNlZEVsZW1lbnQuc2V0SXNGb2N1c2VkKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LCAxMDApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICRzY29wZS5lbGVtZW50LnNldElzRm9jdXNlZEV2ZW50SGFuZGxlcnMucHVzaChmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRlbGVtZW50LnBhcmVudCgpLmZvY3VzKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICRzY29wZS5kZWxldGUgPSBmdW5jdGlvbiAoZWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LmRlbGV0ZSgpO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCRzY29wZS5lbGVtZW50Lmhhc0VkaXRvcikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZWRpdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kcm9vdC5lZGl0RWxlbWVudCgkc2NvcGUuZWxlbWVudCkudGhlbihmdW5jdGlvbiAoYXJncykge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kYXBwbHkoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoYXJncy5jYW5jZWwpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZWxlbWVudC5kYXRhID0gYXJncy5lbGVtZW50LmRhdGE7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5lbGVtZW50LmFwcGx5RWxlbWVudEVkaXRvck1vZGVsKGFyZ3MuZWxlbWVudEVkaXRvck1vZGVsKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghISRzY29wZS5lbGVtZW50LnNldEh0bWwpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZWxlbWVudC5zZXRIdG1sKGFyZ3MuZWxlbWVudC5odG1sKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0sXHJcblxyXG4gICAgICAgICAgICAgICAgY29uZmlndXJlRm9yQ29udGFpbmVyOiBmdW5jdGlvbiAoJHNjb3BlLCAkZWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciBlbGVtZW50ID0gJHNjb3BlLmVsZW1lbnQ7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIC8vJHNjb3BlLmlzUmVjZWl2aW5nID0gZmFsc2U7IC8vIFRydWUgd2hlbiBjb250YWluZXIgaXMgcmVjZWl2aW5nIGFuIGV4dGVybmFsIGVsZW1lbnQgdmlhIGRyYWcvZHJvcC5cclxuICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZ2V0U2hvd0NoaWxkcmVuUGxhY2Vob2xkZXIgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAkc2NvcGUuZWxlbWVudC5jaGlsZHJlbi5sZW5ndGggPT09IDAgJiYgISRzY29wZS5lbGVtZW50LmdldElzRHJvcFRhcmdldCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICRzY29wZS5zb3J0YWJsZU9wdGlvbnMgPSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGN1cnNvcjogXCJtb3ZlXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGF5OiAxNTAsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc2FibGVkOiBlbGVtZW50LmdldElzU2VhbGVkKCksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc3RhbmNlOiA1LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvL2hhbmRsZTogZWxlbWVudC5jaGlsZHJlbi5sZW5ndGggPCAyID8gXCIuaW1hZ2luYXJ5LWNsYXNzXCIgOiBmYWxzZSwgLy8gRm9yIHNvbWUgcmVhc29uIGRvZXNuJ3QgZ2V0IHJlLWV2YWx1YXRlZCBhZnRlciBhZGRpbmcgbW9yZSBjaGlsZHJlbi5cclxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQ6IGZ1bmN0aW9uIChlLCB1aSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLiRhcHBseShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5zZXRJc0Ryb3BUYXJnZXQodHJ1ZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5lZGl0b3IuaXNEcmFnZ2luZyA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1ha2UgdGhlIGRyb3AgdGFyZ2V0IHBsYWNlaG9sZGVyIGFzIGhpZ2ggYXMgdGhlIGl0ZW0gYmVpbmcgZHJhZ2dlZC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpLnBsYWNlaG9sZGVyLmhlaWdodCh1aS5pdGVtLmhlaWdodCgpIC0gNCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aS5wbGFjZWhvbGRlci5jc3MoXCJtaW4taGVpZ2h0XCIsIDApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBzdG9wOiBmdW5jdGlvbiAoZSwgdWkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kYXBwbHkoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuZWRpdG9yLmlzRHJhZ2dpbmcgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LnNldElzRHJvcFRhcmdldChmYWxzZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgb3ZlcjogZnVuY3Rpb24gKGUsIHVpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISF1aS5zZW5kZXIgJiYgISF1aS5zZW5kZXJbMF0uaXNUb29sYm94KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEhdWkuc2VuZGVyWzBdLmRyb3BUYXJnZXRUaW1lb3V0KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICR0aW1lb3V0LmNhbmNlbCh1aS5zZW5kZXJbMF0uZHJvcFRhcmdldFRpbWVvdXQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aS5zZW5kZXJbMF0uZHJvcFRhcmdldFRpbWVvdXQgPSBudWxsO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkdGltZW91dChmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50LnR5cGUgPT0gXCJSb3dcIikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhlcmUgd2FzIGEgcHJldmlvdXMgZHJvcCB0YXJnZXQgYW5kIGl0IHdhcyBhIHJvdywgcm9sbCBiYWNrIGFueSBwZW5kaW5nIGNvbHVtbiBhZGRzIHRvIGl0LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHByZXZpb3VzRHJvcFRhcmdldCA9IGVsZW1lbnQuZWRpdG9yLmRyb3BUYXJnZXRFbGVtZW50O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEhcHJldmlvdXNEcm9wVGFyZ2V0ICYmIHByZXZpb3VzRHJvcFRhcmdldC50eXBlID09IFwiUm93XCIpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJldmlvdXNEcm9wVGFyZ2V0LnJvbGxiYWNrQWRkQ29sdW1uKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5zZXRJc0Ryb3BUYXJnZXQoZmFsc2UpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpLnNlbmRlclswXS5kcm9wVGFyZ2V0VGltZW91dCA9ICR0aW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVsZW1lbnQudHlwZSA9PSBcIlJvd1wiKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVjZWl2ZWRDb2x1bW4gPSB1aS5pdGVtLnNvcnRhYmxlLm1vZGVsO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlY2VpdmVkQ29sdW1uV2lkdGggPSBNYXRoLmZsb29yKDEyIC8gKGVsZW1lbnQuY2hpbGRyZW4ubGVuZ3RoICsgMSkpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZWRDb2x1bW4ud2lkdGggPSByZWNlaXZlZENvbHVtbldpZHRoO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZWRDb2x1bW4ub2Zmc2V0ID0gMDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuYmVnaW5BZGRDb2x1bW4ocmVjZWl2ZWRDb2x1bW5XaWR0aCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNYWtlIHRoZSBkcm9wIHRhcmdldCBwbGFjZWhvbGRlciB0aGUgY29ycmVjdCB3aWR0aCBhbmQgYXMgaGlnaCBhcyB0aGUgaGlnaGVzdCBleGlzdGluZyBjb2x1bW4gaW4gdGhlIHJvdy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBtYXhIZWlnaHQgPSBfLm1heChfKCRlbGVtZW50LmZpbmQoXCI+IC5sYXlvdXQtY2hpbGRyZW4gPiAubGF5b3V0LWNvbHVtbjpub3QoLnVpLXNvcnRhYmxlLXBsYWNlaG9sZGVyKVwiKSkubWFwKGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICQoZSkuaGVpZ2h0KCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGkgPSAxOyBpIDw9IDEyOyBpKyspXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdWkucGxhY2Vob2xkZXIucmVtb3ZlQ2xhc3MoXCJjb2wteHMtXCIgKyBpKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpLnBsYWNlaG9sZGVyLmFkZENsYXNzKFwiY29sLXhzLVwiICsgcmVjZWl2ZWRDb2x1bW4ud2lkdGgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1heEhlaWdodCA+IDApIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aS5wbGFjZWhvbGRlci5oZWlnaHQobWF4SGVpZ2h0KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aS5wbGFjZWhvbGRlci5jc3MoXCJtaW4taGVpZ2h0XCIsIDApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdWkucGxhY2Vob2xkZXIuaGVpZ2h0KDApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpLnBsYWNlaG9sZGVyLmNzcyhcIm1pbi1oZWlnaHRcIiwgXCJcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5zZXRJc0Ryb3BUYXJnZXQodHJ1ZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSwgMTUwKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZTogZnVuY3Rpb24gKGUsIHVpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISF1aS5zZW5kZXIgJiYgISF1aS5zZW5kZXJbMF0uaXNUb29sYm94KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLiRhcHBseShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZWNlaXZlZEVsZW1lbnQgPSB1aS5pdGVtLnNvcnRhYmxlLm1vZGVsO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISFyZWNlaXZlZEVsZW1lbnQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50LnR5cGUgPT0gXCJSb3dcIilcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LmNvbW1pdEFkZENvbHVtbigpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2hvdWxkIGlkZWFsbHkgY2FsbCBMYXlvdXRFZGl0b3IuQ29udGFpbmVyLmFkZENoaWxkKCkgaW5zdGVhZCwgYnV0IHNpbmNlIHRoaXMgaGFuZGxlclxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXMgcnVuICpiZWZvcmUqIHRoZSB1aS1zb3J0YWJsZSBkaXJlY3RpdmUncyBoYW5kbGVyLCBpZiB3ZSB0cnkgdG8gYWRkIHRoZSBjaGlsZCB0byB0aGVcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFycmF5IHRoYXQgaGFuZGxlciB3aWxsIGdldCBhbiBleGNlcHRpb24gd2hlbiB0cnlpbmcgdG8gZG8gdGhlIHNhbWUuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBCZWNhdXNlIG9mIHRoaXMsIHdlIG5lZWQgdG8gaW52b2tlIFwic2V0UGFyZW50XCIgc28gdGhhdCBzcGVjaWZpYyBjb250YWluZXIgdHlwZXMgY2FuIHBlcmZvcm0gZWxlbWVudCBzcGVmaWNpYyBpbml0aWFsaXphdGlvbi5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmVkRWxlbWVudC5zZXRFZGl0b3IoZWxlbWVudC5lZGl0b3IpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZWRFbGVtZW50LnNldFBhcmVudChlbGVtZW50KTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISFyZWNlaXZlZEVsZW1lbnQuaGFzRWRpdG9yKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLiRyb290LmVkaXRFbGVtZW50KHJlY2VpdmVkRWxlbWVudCkudGhlbihmdW5jdGlvbiAoYXJncykge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWFyZ3MuY2FuY2VsKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNlaXZlZEVsZW1lbnQuZGF0YSA9IGFyZ3MuZWxlbWVudC5kYXRhO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZWRFbGVtZW50LmFwcGx5RWxlbWVudEVkaXRvck1vZGVsKGFyZ3MuZWxlbWVudEVkaXRvck1vZGVsKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISFyZWNlaXZlZEVsZW1lbnQuc2V0SHRtbClcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNlaXZlZEVsZW1lbnQuc2V0SHRtbChhcmdzLmVsZW1lbnQuaHRtbCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHRpbWVvdXQoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEhYXJncy5jYW5jZWwpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZWRFbGVtZW50LmRlbGV0ZSgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmVkRWxlbWVudC5zZXRJc0ZvY3VzZWQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vJHNjb3BlLmlzUmVjZWl2aW5nID0gZmFsc2U7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LnNldElzRHJvcFRhcmdldChmYWxzZSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICR0aW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vJHNjb3BlLmlzUmVjZWl2aW5nID0gZmFsc2U7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LnNldElzRHJvcFRhcmdldChmYWxzZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISFyZWNlaXZlZEVsZW1lbnQpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZWRFbGVtZW50LnNldElzRm9jdXNlZCgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICRzY29wZS5jbGljayA9IGZ1bmN0aW9uIChjaGlsZCwgZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWNoaWxkLmVkaXRvci5pc0RyYWdnaW5nKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hpbGQuc2V0SXNGb2N1c2VkKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmdldENsYXNzZXMgPSBmdW5jdGlvbiAoY2hpbGQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlc3VsdCA9IFtcImxheW91dC1lbGVtZW50XCJdO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEhY2hpbGQuY2hpbGRyZW4pIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKFwibGF5b3V0LWNvbnRhaW5lclwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjaGlsZC5nZXRJc1NlYWxlZCgpKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKFwibGF5b3V0LWNvbnRhaW5lci1zZWFsZWRcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKFwibGF5b3V0LVwiICsgY2hpbGQudHlwZS50b0xvd2VyQ2FzZSgpKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghIWNoaWxkLmRyb3BUYXJnZXRDbGFzcylcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKGNoaWxkLmRyb3BUYXJnZXRDbGFzcyk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBUT0RPOiBNb3ZlIHRoZXNlIHRvIGVpdGhlciB0aGUgQ29sdW1uIGRpcmVjdGl2ZSBvciB0aGUgQ29sdW1uIG1vZGVsIGNsYXNzLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2hpbGQudHlwZSA9PSBcIlJvd1wiKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChcInJvd1wiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghY2hpbGQuY2FuQWRkQ29sdW1uKCkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goXCJsYXlvdXQtcm93LWZ1bGxcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNoaWxkLnR5cGUgPT0gXCJDb2x1bW5cIikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goXCJjb2wteHMtXCIgKyBjaGlsZC53aWR0aCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChcImNvbC14cy1vZmZzZXQtXCIgKyBjaGlsZC5vZmZzZXQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjaGlsZC50eXBlID09IFwiQ29udGVudFwiKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goXCJsYXlvdXQtY29udGVudC1cIiArIGNoaWxkLmNvbnRlbnRUeXBlQ2xhc3MpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNoaWxkLmdldElzQWN0aXZlKCkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChcImxheW91dC1lbGVtZW50LWFjdGl2ZVwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNoaWxkLmdldElzRm9jdXNlZCgpKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goXCJsYXlvdXQtZWxlbWVudC1mb2N1c2VkXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2hpbGQuZ2V0SXNTZWxlY3RlZCgpKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goXCJsYXlvdXQtZWxlbWVudC1zZWxlY3RlZFwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNoaWxkLmdldElzRHJvcFRhcmdldCgpKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goXCJsYXlvdXQtZWxlbWVudC1kcm9wdGFyZ2V0XCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2hpbGQuaXNUZW1wbGF0ZWQpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChcImxheW91dC1lbGVtZW50LXRlbXBsYXRlZFwiKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICAgICAgICAgICAgICAgICAgfTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfTtcclxuICAgICAgICB9XHJcbiAgICBdKTsiLCJhbmd1bGFyXHJcbiAgICAubW9kdWxlKFwiTGF5b3V0RWRpdG9yXCIpXHJcbiAgICAuZGlyZWN0aXZlKFwib3JjTGF5b3V0RWRpdG9yXCIsIFtcImVudmlyb25tZW50XCIsXHJcbiAgICAgICAgZnVuY3Rpb24gKGVudmlyb25tZW50KSB7XHJcbiAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICByZXN0cmljdDogXCJFXCIsXHJcbiAgICAgICAgICAgICAgICBzY29wZToge30sXHJcbiAgICAgICAgICAgICAgICBjb250cm9sbGVyOiBbXCIkc2NvcGVcIiwgXCIkZWxlbWVudFwiLCBcIiRhdHRyc1wiLCBcIiRjb21waWxlXCIsIFwiY2xpcGJvYXJkXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCRzY29wZSwgJGVsZW1lbnQsICRhdHRycywgJGNvbXBpbGUsIGNsaXBib2FyZCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoISEkYXR0cnMubW9kZWwpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZWxlbWVudCA9IGV2YWwoJGF0dHJzLm1vZGVsKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVGhlICdtb2RlbCcgYXR0cmlidXRlIG11c3QgZXZhbHVhdGUgdG8gYSBMYXlvdXRFZGl0b3IuRWRpdG9yIG9iamVjdC5cIik7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuY2xpY2sgPSBmdW5jdGlvbiAoY2FudmFzLCBlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWNhbnZhcy5lZGl0b3IuaXNEcmFnZ2luZylcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYW52YXMuc2V0SXNGb2N1c2VkKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmdldENsYXNzZXMgPSBmdW5jdGlvbiAoY2FudmFzKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVzdWx0ID0gW1wibGF5b3V0LWVsZW1lbnRcIiwgXCJsYXlvdXQtY29udGFpbmVyXCIsIFwibGF5b3V0LWNhbnZhc1wiXTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2FudmFzLmdldElzQWN0aXZlKCkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goXCJsYXlvdXQtZWxlbWVudC1hY3RpdmVcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2FudmFzLmdldElzRm9jdXNlZCgpKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKFwibGF5b3V0LWVsZW1lbnQtZm9jdXNlZFwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjYW52YXMuZ2V0SXNTZWxlY3RlZCgpKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKFwibGF5b3V0LWVsZW1lbnQtc2VsZWN0ZWRcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2FudmFzLmdldElzRHJvcFRhcmdldCgpKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKFwibGF5b3V0LWVsZW1lbnQtZHJvcHRhcmdldFwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjYW52YXMuaXNUZW1wbGF0ZWQpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goXCJsYXlvdXQtZWxlbWVudC10ZW1wbGF0ZWRcIik7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFuIHVuZm9ydHVuYXRlIHNpZGUtZWZmZWN0IG9mIHRoZSBuZXh0IGhhY2sgb24gbGluZSA1NCBpcyB0aGF0IHRoZSBjcmVhdGVkIGVsZW1lbnRzIGFyZW4ndCBhZGRlZCB0byB0aGUgRE9NIHlldCwgc28gd2UgY2FuJ3QgdXNlIGl0IHRvIGdldCB0byB0aGUgcGFyZW50IFwiLmxheW91dC1kZXNpZ2VyXCIgZWxlbWVudC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gV29yayBhcm91bmQ6IGFjY2VzcyB0aGF0IGVsZW1lbnQgZGlyZWN0bHkgKHdoaWNoIGVmZWN0aXZlbHkgdHVybnMgbXVsdGlwbGUgbGF5b3V0IGVkaXRvcnMgb24gYSBzaW5nbGUgcGFnZSBpbXBvc3NpYmxlKS4gXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIC8vdmFyIGxheW91dERlc2lnbmVySG9zdCA9ICRlbGVtZW50LmNsb3Nlc3QoXCIubGF5b3V0LWRlc2lnbmVyXCIpLmRhdGEoXCJsYXlvdXQtZGVzaWduZXItaG9zdFwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGxheW91dERlc2lnbmVySG9zdCA9ICQoXCIubGF5b3V0LWRlc2lnbmVyXCIpLmRhdGEoXCJsYXlvdXQtZGVzaWduZXItaG9zdFwiKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kcm9vdC5sYXlvdXREZXNpZ25lckhvc3QgPSBsYXlvdXREZXNpZ25lckhvc3Q7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBsYXlvdXREZXNpZ25lckhvc3QuZWxlbWVudC5vbihcInJlcGxhY2VjYW52YXNcIiwgZnVuY3Rpb24gKGUsIGFyZ3MpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBlZGl0b3IgPSAkc2NvcGUuZWxlbWVudDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBjYW52YXNEYXRhID0ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE6IGFyZ3MuY2FudmFzLmRhdGEsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaHRtbElkOiBhcmdzLmNhbnZhcy5odG1sSWQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaHRtbENsYXNzOiBhcmdzLmNhbnZhcy5odG1sQ2xhc3MsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaHRtbFN0eWxlOiBhcmdzLmNhbnZhcy5odG1sU3R5bGUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNUZW1wbGF0ZWQ6IGFyZ3MuY2FudmFzLmlzVGVtcGxhdGVkLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBhcmdzLmNhbnZhcy5jaGlsZHJlblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBIQUNLOiBJbnN0ZWFkIG9mIHNpbXBseSB1cGRhdGluZyB0aGUgJHNjb3BlLmVsZW1lbnQgd2l0aCBhIG5ldyBpbnN0YW5jZSwgd2UgbmVlZCB0byByZXBsYWNlIHRoZSBlbnRpcmUgb3JjLWxheW91dC1lZGl0b3IgbWFya3VwXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpbiBvcmRlciBmb3IgYW5ndWxhciB0byByZWJpbmQgc3RhcnRpbmcgd2l0aCB0aGUgQ2FudmFzIGVsZW1lbnQuIE90aGVyd2lzZSwgZm9yIHNvbWUgcmVhc29uLCBpdCB3aWxsIHJlYmluZCBzdGFydGluZyB3aXRoIHRoZSBmaXJzdCBjaGlsZCBvZiBDYW52YXMuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBZb3UgY2FuIHNlZSB0aGlzIGhhcHBlbmluZyB3aGVuIHNldHRpbmcgYSBicmVha3BvaW50IGluIFNjb3BlQ29uZmlndXJhdG9yIHdoZXJlIGNvbnRhaW5lcnMgYXJlIGluaXRpYWxpemVkIHdpdGggZHJhZyAmIGRyb3A6IG9uIHBhZ2UgbG9hZCwgdGhlIGZpcnN0IGVsZW1lbnRcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlzIGEgQ2FudmFzIChnb29kKSwgYnV0IGFmdGVyIGhhdmluZyBzZWxlY3RlZCBhbm90aGVyIHRlbXBsYXRlLCB0aGUgZmlyc3QgZWxlbWVudCBpcyAodHlwaWNhbGx5KSBhIEdyaWQgKGJhZCkuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaW1wbHkgcmVjb21waWxpbmcgdGhlIG9yYy1sYXlvdXQtZWRpdG9yIGRpcmVjdGl2ZSB3aWxsIGNhdXNlIHRoZSBlbnRpcmUgdGhpbmcgdG8gYmUgZ2VuZXJhdGVkLCB3aGljaCB3b3JrcyBqdXN0IGZpbmUgYXMgd2VsbCAoZXZlbiB0aG91Z2ggbm90IGlzIG5pY2UgYXMgc2ltcGx5IGxldmVyYWdpbmcgbW9kZWwgYmluZGluZykuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXlvdXREZXNpZ25lckhvc3QuZWRpdG9yID0gd2luZG93LmxheW91dEVkaXRvciA9IG5ldyBMYXlvdXRFZGl0b3IuRWRpdG9yKGVkaXRvci5jb25maWcsIGNhbnZhc0RhdGEpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHRlbXBsYXRlID0gXCI8b3JjLWxheW91dC1lZGl0b3JcIiArIFwiIG1vZGVsPSd3aW5kb3cubGF5b3V0RWRpdG9yJyAvPlwiO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGh0bWwgPSAkY29tcGlsZSh0ZW1wbGF0ZSkoJHNjb3BlKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoXCIubGF5b3V0LWVkaXRvci1ob2xkZXJcIikuaHRtbChodG1sKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuJHJvb3QuZWRpdEVsZW1lbnQgPSBmdW5jdGlvbiAoZWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGhvc3QgPSAkc2NvcGUuJHJvb3QubGF5b3V0RGVzaWduZXJIb3N0O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGhvc3QuZWRpdEVsZW1lbnQoZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuJHJvb3QuYWRkRWxlbWVudCA9IGZ1bmN0aW9uIChjb250ZW50VHlwZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGhvc3QgPSAkc2NvcGUuJHJvb3QubGF5b3V0RGVzaWduZXJIb3N0O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGhvc3QuYWRkRWxlbWVudChjb250ZW50VHlwZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS5vbihcImN1dCBjb3B5IHBhc3RlXCIsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiB0aGUgcHNldWRvIGNsaXBib2FyZCB3YXMgYWxyZWFkeSBpbnZva2VkICh3aGljaCBoYXBwZW5zIG9uIHRoZSBmaXJzdCBjbGlwYm9hcmRcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9wZXJhdGlvbiBhZnRlciBwYWdlIGxvYWQgZXZlbiBpZiBuYXRpdmUgY2xpcGJvYXJkIHN1cHBvcnQgZXhpc3RzKSB0aGVuIHNpdCB0aGlzXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBvbmUgb3BlcmF0aW9uIG91dCwgYnV0IG1ha2Ugc3VyZSB3aGF0ZXZlciBpcyBvbiB0aGUgcHNldWRvIGNsaXBib2FyZCBnZXRzIG1pZ3JhdGVkXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0byB0aGUgbmF0aXZlIGNsaXBib2FyZCBmb3Igc3Vic2VxdWVudCBvcGVyYXRpb25zLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNsaXBib2FyZC53YXNJbnZva2VkKCkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLm9yaWdpbmFsRXZlbnQuY2xpcGJvYXJkRGF0YS5zZXREYXRhKFwidGV4dC9wbGFpblwiLCBjbGlwYm9hcmQuZ2V0RGF0YShcInRleHQvcGxhaW5cIikpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGUub3JpZ2luYWxFdmVudC5jbGlwYm9hcmREYXRhLnNldERhdGEoXCJ0ZXh0L2pzb25cIiwgY2xpcGJvYXJkLmdldERhdGEoXCJ0ZXh0L2pzb25cIikpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBmb2N1c2VkRWxlbWVudCA9ICRzY29wZS5lbGVtZW50LmZvY3VzZWRFbGVtZW50O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghIWZvY3VzZWRFbGVtZW50KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kYXBwbHkoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3dpdGNoIChlLnR5cGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwiY29weVwiOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb2N1c2VkRWxlbWVudC5jb3B5KGUub3JpZ2luYWxFdmVudC5jbGlwYm9hcmREYXRhKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcImN1dFwiOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb2N1c2VkRWxlbWVudC5jdXQoZS5vcmlnaW5hbEV2ZW50LmNsaXBib2FyZERhdGEpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwicGFzdGVcIjpcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9jdXNlZEVsZW1lbnQucGFzdGUoZS5vcmlnaW5hbEV2ZW50LmNsaXBib2FyZERhdGEpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBIQUNLOiBXb3JrYXJvdW5kIGJlY2F1c2Ugb2YgaG93IEFuZ3VsYXIgdHJlYXRzIHRoZSBET00gd2hlbiBlbGVtZW50cyBhcmUgc2hpZnRlZCBhcm91bmQgLSBpbnB1dCBmb2N1cyBpcyBzb21ldGltZXMgbG9zdC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLiRhcHBseShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEhJHNjb3BlLmVsZW1lbnQuZm9jdXNlZEVsZW1lbnQpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5lbGVtZW50LmZvY3VzZWRFbGVtZW50LnNldElzRm9jdXNlZCgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sIDEwMCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5hdGl2ZSBjbGlwYm9hcmQgc3VwcG9ydCBvYnZpb3VzbHkgZXhpc3RzLCBzbyBkaXNhYmxlIHRoZSBwZXVkbyBjbGlwYm9hcmQgZnJvbSBub3cgb24uXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGlwYm9hcmQuZGlzYWJsZSgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBdLFxyXG4gICAgICAgICAgICAgICAgdGVtcGxhdGVVcmw6IGVudmlyb25tZW50LnRlbXBsYXRlVXJsKFwiRWRpdG9yXCIpLFxyXG4gICAgICAgICAgICAgICAgcmVwbGFjZTogdHJ1ZSxcclxuICAgICAgICAgICAgICAgIGxpbms6IGZ1bmN0aW9uIChzY29wZSwgZWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIE5vIGNsaWNrcyBzaG91bGQgcHJvcGFnYXRlIGZyb20gdGhlIFRpbnlNQ0UgdG9vbGJhcnMuXHJcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5maW5kKFwiLmxheW91dC10b29sYmFyLWNvbnRhaW5lclwiKS5jbGljayhmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFVuZm9jdXMgYW5kIHVuc2VsZWN0IGV2ZXJ5dGhpbmcgb24gY2xpY2sgb3V0c2lkZSBvZiBjYW52YXMuXHJcbiAgICAgICAgICAgICAgICAgICAgJCh3aW5kb3cpLmNsaWNrKGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjb3BlLiRhcHBseShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY29wZS5lbGVtZW50LmFjdGl2ZUVsZW1lbnQgPSBudWxsO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGUuZWxlbWVudC5mb2N1c2VkRWxlbWVudCA9IG51bGw7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9O1xyXG4gICAgICAgIH1cclxuICAgIF0pOyIsImFuZ3VsYXJcclxuICAgIC5tb2R1bGUoXCJMYXlvdXRFZGl0b3JcIilcclxuICAgIC5kaXJlY3RpdmUoXCJvcmNMYXlvdXRDYW52YXNcIiwgW1wic2NvcGVDb25maWd1cmF0b3JcIiwgXCJlbnZpcm9ubWVudFwiLFxyXG4gICAgICAgIGZ1bmN0aW9uIChzY29wZUNvbmZpZ3VyYXRvciwgZW52aXJvbm1lbnQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICAgIHJlc3RyaWN0OiBcIkVcIixcclxuICAgICAgICAgICAgICAgIHNjb3BlOiB7IGVsZW1lbnQ6IFwiPVwiIH0sXHJcbiAgICAgICAgICAgICAgICBjb250cm9sbGVyOiBbXCIkc2NvcGVcIiwgXCIkZWxlbWVudFwiLCBcIiRhdHRyc1wiLFxyXG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uICgkc2NvcGUsICRlbGVtZW50LCAkYXR0cnMpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGVDb25maWd1cmF0b3IuY29uZmlndXJlRm9yRWxlbWVudCgkc2NvcGUsICRlbGVtZW50KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGVDb25maWd1cmF0b3IuY29uZmlndXJlRm9yQ29udGFpbmVyKCRzY29wZSwgJGVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuc29ydGFibGVPcHRpb25zW1wiYXhpc1wiXSA9IFwieVwiO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIF0sXHJcbiAgICAgICAgICAgICAgICB0ZW1wbGF0ZVVybDogZW52aXJvbm1lbnQudGVtcGxhdGVVcmwoXCJDYW52YXNcIiksXHJcbiAgICAgICAgICAgICAgICByZXBsYWNlOiB0cnVlXHJcbiAgICAgICAgICAgIH07XHJcbiAgICAgICAgfVxyXG4gICAgXSk7IiwiYW5ndWxhclxyXG4gICAgLm1vZHVsZShcIkxheW91dEVkaXRvclwiKVxyXG4gICAgLmRpcmVjdGl2ZShcIm9yY0xheW91dENoaWxkXCIsIFtcIiRjb21waWxlXCIsXHJcbiAgICAgICAgZnVuY3Rpb24gKCRjb21waWxlKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICByZXN0cmljdDogXCJFXCIsXHJcbiAgICAgICAgICAgICAgICBzY29wZTogeyBlbGVtZW50OiBcIj1cIiB9LFxyXG4gICAgICAgICAgICAgICAgbGluazogZnVuY3Rpb24gKHNjb3BlLCBlbGVtZW50KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdmFyIHRlbXBsYXRlID0gXCI8b3JjLWxheW91dC1cIiArIHNjb3BlLmVsZW1lbnQudHlwZS50b0xvd2VyQ2FzZSgpICsgXCIgZWxlbWVudD0nZWxlbWVudCcgLz5cIjtcclxuICAgICAgICAgICAgICAgICAgICB2YXIgaHRtbCA9ICRjb21waWxlKHRlbXBsYXRlKShzY29wZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgJChlbGVtZW50KS5yZXBsYWNlV2l0aChodG1sKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfTtcclxuICAgICAgICB9XHJcbiAgICBdKTsiLCJhbmd1bGFyXHJcbiAgICAubW9kdWxlKFwiTGF5b3V0RWRpdG9yXCIpXHJcbiAgICAuZGlyZWN0aXZlKFwib3JjTGF5b3V0Q29sdW1uXCIsIFtcIiRjb21waWxlXCIsIFwic2NvcGVDb25maWd1cmF0b3JcIiwgXCJlbnZpcm9ubWVudFwiLFxyXG4gICAgICAgIGZ1bmN0aW9uICgkY29tcGlsZSwgc2NvcGVDb25maWd1cmF0b3IsIGVudmlyb25tZW50KSB7XHJcbiAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICByZXN0cmljdDogXCJFXCIsXHJcbiAgICAgICAgICAgICAgICBzY29wZTogeyBlbGVtZW50OiBcIj1cIiB9LFxyXG4gICAgICAgICAgICAgICAgY29udHJvbGxlcjogW1wiJHNjb3BlXCIsIFwiJGVsZW1lbnRcIixcclxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoJHNjb3BlLCAkZWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBzY29wZUNvbmZpZ3VyYXRvci5jb25maWd1cmVGb3JFbGVtZW50KCRzY29wZSwgJGVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBzY29wZUNvbmZpZ3VyYXRvci5jb25maWd1cmVGb3JDb250YWluZXIoJHNjb3BlLCAkZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5zb3J0YWJsZU9wdGlvbnNbXCJheGlzXCJdID0gXCJ5XCI7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgXSxcclxuICAgICAgICAgICAgICAgIHRlbXBsYXRlVXJsOiBlbnZpcm9ubWVudC50ZW1wbGF0ZVVybChcIkNvbHVtblwiKSxcclxuICAgICAgICAgICAgICAgIHJlcGxhY2U6IHRydWUsXHJcbiAgICAgICAgICAgICAgICBsaW5rOiBmdW5jdGlvbiAoc2NvcGUsIGVsZW1lbnQsIGF0dHJzKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5maW5kKFwiLmxheW91dC1jb2x1bW4tcmVzaXplLWJhclwiKS5kcmFnZ2FibGUoe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBheGlzOiBcInhcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgaGVscGVyOiBcImNsb25lXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldmVydDogdHJ1ZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQ6IGZ1bmN0aW9uIChlLCB1aSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGUuJGFwcGx5KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY29wZS5lbGVtZW50LmVkaXRvci5pc1Jlc2l6aW5nID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBkcmFnOiBmdW5jdGlvbiAoZSwgdWkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBjb2x1bW5FbGVtZW50ID0gZWxlbWVudC5wYXJlbnQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBjb2x1bW5TaXplID0gY29sdW1uRWxlbWVudC53aWR0aCgpIC8gc2NvcGUuZWxlbWVudC53aWR0aDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBjb25uZWN0QWRqYWNlbnQgPSAhZS5jdHJsS2V5O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCQoZS50YXJnZXQpLmhhc0NsYXNzKFwibGF5b3V0LWNvbHVtbi1yZXNpemUtYmFyLWxlZnRcIikpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgZGVsdGEgPSB1aS5vZmZzZXQubGVmdCAtIGNvbHVtbkVsZW1lbnQub2Zmc2V0KCkubGVmdDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZGVsdGEgPCAtY29sdW1uU2l6ZSAmJiBzY29wZS5lbGVtZW50LmNhbkV4cGFuZExlZnQoY29ubmVjdEFkamFjZW50KSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY29wZS4kYXBwbHkoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGUuZWxlbWVudC5leHBhbmRMZWZ0KGNvbm5lY3RBZGphY2VudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChkZWx0YSA+IGNvbHVtblNpemUgJiYgc2NvcGUuZWxlbWVudC5jYW5Db250cmFjdExlZnQoY29ubmVjdEFkamFjZW50KSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY29wZS4kYXBwbHkoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGUuZWxlbWVudC5jb250cmFjdExlZnQoY29ubmVjdEFkamFjZW50KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoJChlLnRhcmdldCkuaGFzQ2xhc3MoXCJsYXlvdXQtY29sdW1uLXJlc2l6ZS1iYXItcmlnaHRcIikpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgZGVsdGEgPSB1aS5vZmZzZXQubGVmdCAtIGNvbHVtbkVsZW1lbnQud2lkdGgoKSAtIGNvbHVtbkVsZW1lbnQub2Zmc2V0KCkubGVmdDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZGVsdGEgPiBjb2x1bW5TaXplICYmIHNjb3BlLmVsZW1lbnQuY2FuRXhwYW5kUmlnaHQoY29ubmVjdEFkamFjZW50KSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY29wZS4kYXBwbHkoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGUuZWxlbWVudC5leHBhbmRSaWdodChjb25uZWN0QWRqYWNlbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoZGVsdGEgPCAtY29sdW1uU2l6ZSAmJiBzY29wZS5lbGVtZW50LmNhbkNvbnRyYWN0UmlnaHQoY29ubmVjdEFkamFjZW50KSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY29wZS4kYXBwbHkoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGUuZWxlbWVudC5jb250cmFjdFJpZ2h0KGNvbm5lY3RBZGphY2VudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0b3A6IGZ1bmN0aW9uIChlLCB1aSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGUuJGFwcGx5KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGUuZWxlbWVudC5lZGl0b3IuaXNSZXNpemluZyA9IGZhbHNlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfTtcclxuICAgICAgICB9XHJcbiAgICBdKTsiLCJhbmd1bGFyXHJcbiAgICAubW9kdWxlKFwiTGF5b3V0RWRpdG9yXCIpXHJcbiAgICAuZGlyZWN0aXZlKFwib3JjTGF5b3V0Q29udGVudFwiLCBbXCIkc2NlXCIsIFwic2NvcGVDb25maWd1cmF0b3JcIiwgXCJlbnZpcm9ubWVudFwiLFxyXG4gICAgICAgIGZ1bmN0aW9uICgkc2NlLCBzY29wZUNvbmZpZ3VyYXRvciwgZW52aXJvbm1lbnQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICAgIHJlc3RyaWN0OiBcIkVcIixcclxuICAgICAgICAgICAgICAgIHNjb3BlOiB7IGVsZW1lbnQ6IFwiPVwiIH0sXHJcbiAgICAgICAgICAgICAgICBjb250cm9sbGVyOiBbXCIkc2NvcGVcIiwgXCIkZWxlbWVudFwiLFxyXG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uICgkc2NvcGUsICRlbGVtZW50KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjb3BlQ29uZmlndXJhdG9yLmNvbmZpZ3VyZUZvckVsZW1lbnQoJHNjb3BlLCAkZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBPdmVyd3JpdGUgdGhlIHNldEh0bWwgZnVuY3Rpb24gc28gdGhhdCB3ZSBjYW4gdXNlIHRoZSAkc2NlIHNlcnZpY2UgdG8gdHJ1c3QgdGhlIGh0bWwgKGFuZCBub3QgaGF2ZSB0aGUgaHRtbCBiaW5kaW5nIHN0cmlwIGNlcnRhaW4gdGFncykuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5lbGVtZW50LnNldEh0bWwgPSBmdW5jdGlvbiAoaHRtbCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmVsZW1lbnQuaHRtbCA9IGh0bWw7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZWxlbWVudC5odG1sVW5zYWZlID0gJHNjZS50cnVzdEFzSHRtbChodG1sKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5lbGVtZW50LnNldEh0bWwoJHNjb3BlLmVsZW1lbnQuaHRtbCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgXSxcclxuICAgICAgICAgICAgICAgIHRlbXBsYXRlVXJsOiBlbnZpcm9ubWVudC50ZW1wbGF0ZVVybChcIkNvbnRlbnRcIiksXHJcbiAgICAgICAgICAgICAgICByZXBsYWNlOiB0cnVlXHJcbiAgICAgICAgICAgIH07XHJcbiAgICAgICAgfVxyXG4gICAgXSk7IiwiYW5ndWxhclxyXG4gICAgLm1vZHVsZShcIkxheW91dEVkaXRvclwiKVxyXG4gICAgLmRpcmVjdGl2ZShcIm9yY0xheW91dEdyaWRcIiwgW1wiJGNvbXBpbGVcIiwgXCJzY29wZUNvbmZpZ3VyYXRvclwiLCBcImVudmlyb25tZW50XCIsXHJcbiAgICAgICAgZnVuY3Rpb24gKCRjb21waWxlLCBzY29wZUNvbmZpZ3VyYXRvciwgZW52aXJvbm1lbnQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICAgIHJlc3RyaWN0OiBcIkVcIixcclxuICAgICAgICAgICAgICAgIHNjb3BlOiB7IGVsZW1lbnQ6IFwiPVwiIH0sXHJcbiAgICAgICAgICAgICAgICBjb250cm9sbGVyOiBbXCIkc2NvcGVcIiwgXCIkZWxlbWVudFwiLFxyXG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uICgkc2NvcGUsICRlbGVtZW50KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjb3BlQ29uZmlndXJhdG9yLmNvbmZpZ3VyZUZvckVsZW1lbnQoJHNjb3BlLCAkZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjb3BlQ29uZmlndXJhdG9yLmNvbmZpZ3VyZUZvckNvbnRhaW5lcigkc2NvcGUsICRlbGVtZW50KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLnNvcnRhYmxlT3B0aW9uc1tcImF4aXNcIl0gPSBcInlcIjtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBdLFxyXG4gICAgICAgICAgICAgICAgdGVtcGxhdGVVcmw6IGVudmlyb25tZW50LnRlbXBsYXRlVXJsKFwiR3JpZFwiKSxcclxuICAgICAgICAgICAgICAgIHJlcGxhY2U6IHRydWVcclxuICAgICAgICAgICAgfTtcclxuICAgICAgICB9XHJcbiAgICBdKTsiLCJhbmd1bGFyXHJcbiAgICAubW9kdWxlKFwiTGF5b3V0RWRpdG9yXCIpXHJcbiAgICAuZGlyZWN0aXZlKFwib3JjTGF5b3V0Um93XCIsIFtcIiRjb21waWxlXCIsIFwic2NvcGVDb25maWd1cmF0b3JcIiwgXCJlbnZpcm9ubWVudFwiLFxyXG4gICAgICAgIGZ1bmN0aW9uICgkY29tcGlsZSwgc2NvcGVDb25maWd1cmF0b3IsIGVudmlyb25tZW50KSB7XHJcbiAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICByZXN0cmljdDogXCJFXCIsXHJcbiAgICAgICAgICAgICAgICBzY29wZTogeyBlbGVtZW50OiBcIj1cIiB9LFxyXG4gICAgICAgICAgICAgICAgY29udHJvbGxlcjogW1wiJHNjb3BlXCIsIFwiJGVsZW1lbnRcIixcclxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoJHNjb3BlLCAkZWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBzY29wZUNvbmZpZ3VyYXRvci5jb25maWd1cmVGb3JFbGVtZW50KCRzY29wZSwgJGVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBzY29wZUNvbmZpZ3VyYXRvci5jb25maWd1cmVGb3JDb250YWluZXIoJHNjb3BlLCAkZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5zb3J0YWJsZU9wdGlvbnNbXCJheGlzXCJdID0gXCJ4XCI7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5zb3J0YWJsZU9wdGlvbnNbXCJ1aS1mbG9hdGluZ1wiXSA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgXSxcclxuICAgICAgICAgICAgICAgIHRlbXBsYXRlVXJsOiBlbnZpcm9ubWVudC50ZW1wbGF0ZVVybChcIlJvd1wiKSxcclxuICAgICAgICAgICAgICAgIHJlcGxhY2U6IHRydWVcclxuICAgICAgICAgICAgfTtcclxuICAgICAgICB9XHJcbiAgICBdKTsiLCJhbmd1bGFyXHJcbiAgICAubW9kdWxlKFwiTGF5b3V0RWRpdG9yXCIpXHJcbiAgICAuZGlyZWN0aXZlKFwib3JjTGF5b3V0UG9wdXBcIiwgW1xyXG4gICAgICAgIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICAgIHJlc3RyaWN0OiBcIkFcIixcclxuICAgICAgICAgICAgICAgIGxpbms6IGZ1bmN0aW9uIChzY29wZSwgZWxlbWVudCwgYXR0cnMpIHtcclxuICAgICAgICAgICAgICAgICAgICB2YXIgcG9wdXAgPSAkKGVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciB0cmlnZ2VyID0gcG9wdXAuY2xvc2VzdChcIi5sYXlvdXQtcG9wdXAtdHJpZ2dlclwiKTtcclxuICAgICAgICAgICAgICAgICAgICB2YXIgcGFyZW50RWxlbWVudCA9IHBvcHVwLmNsb3Nlc3QoXCIubGF5b3V0LWVsZW1lbnRcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgdHJpZ2dlci5jbGljayhmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVwLnRvZ2dsZSgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAocG9wdXAuaXMoXCI6dmlzaWJsZVwiKSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdXAucG9zaXRpb24oe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG15OiBhdHRycy5vcmNMYXlvdXRQb3B1cE15IHx8IFwibGVmdCB0b3BcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdDogYXR0cnMub3JjTGF5b3V0UG9wdXBBdCB8fCBcImxlZnQgYm90dG9tKzRweFwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9mOiB0cmlnZ2VyXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVwLmZpbmQoXCJpbnB1dFwiKS5maXJzdCgpLmZvY3VzKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICBwb3B1cC5jbGljayhmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgIHBhcmVudEVsZW1lbnQuY2xpY2soZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgcG9wdXAuaGlkZSgpO1xyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgIHBvcHVwLmtleWRvd24oZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFlLmN0cmxLZXkgJiYgIWUuc2hpZnRLZXkgJiYgIWUuYWx0S2V5ICYmIGUud2hpY2ggPT0gMjcpIC8vIEVzY1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdXAuaGlkZSgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgIHBvcHVwLm9uKFwiY3V0IGNvcHkgcGFzdGVcIiwgZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWxsb3cgY2xpcGJvYXJkIG9wZXJhdGlvbnMgaW4gcG9wdXAgd2l0aG91dCBpbnZva2luZyBjbGlwYm9hcmQgZXZlbnQgaGFuZGxlcnMgb24gcGFyZW50IGVsZW1lbnQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH07XHJcbiAgICAgICAgfVxyXG4gICAgXSk7IiwiYW5ndWxhclxyXG4gICAgLm1vZHVsZShcIkxheW91dEVkaXRvclwiKVxyXG4gICAgLmRpcmVjdGl2ZShcIm9yY0xheW91dFRvb2xib3hcIiwgW1wiJGNvbXBpbGVcIiwgXCJlbnZpcm9ubWVudFwiLFxyXG4gICAgICAgIGZ1bmN0aW9uICgkY29tcGlsZSwgZW52aXJvbm1lbnQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICAgIHJlc3RyaWN0OiBcIkVcIixcclxuICAgICAgICAgICAgICAgIGNvbnRyb2xsZXI6IFtcIiRzY29wZVwiLCBcIiRlbGVtZW50XCIsXHJcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCRzY29wZSwgJGVsZW1lbnQpIHtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5yZXNldEVsZW1lbnRzID0gZnVuY3Rpb24gKCkge1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5ncmlkRWxlbWVudHMgPSBbXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTGF5b3V0RWRpdG9yLkdyaWQuZnJvbSh7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hJY29uOiBcIlxcdWYwMGFcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveExhYmVsOiBcIkdyaWRcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveERlc2NyaXB0aW9uOiBcIkVtcHR5IGdyaWQuXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBbXVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5yb3dFbGVtZW50cyA9IFtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMYXlvdXRFZGl0b3IuUm93LmZyb20oe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94SWNvbjogXCJcXHVmMGM5XCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hMYWJlbDogXCJSb3cgKDEgY29sdW1uKVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94RGVzY3JpcHRpb246IFwiUm93IHdpdGggMSBjb2x1bW4uXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBMYXlvdXRFZGl0b3IuQ29sdW1uLnRpbWVzKDEpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTGF5b3V0RWRpdG9yLlJvdy5mcm9tKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveEljb246IFwiXFx1ZjBjOVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94TGFiZWw6IFwiUm93ICgyIGNvbHVtbnMpXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hEZXNjcmlwdGlvbjogXCJSb3cgd2l0aCAyIGNvbHVtbnMuXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBMYXlvdXRFZGl0b3IuQ29sdW1uLnRpbWVzKDIpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTGF5b3V0RWRpdG9yLlJvdy5mcm9tKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveEljb246IFwiXFx1ZjBjOVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94TGFiZWw6IFwiUm93ICgzIGNvbHVtbnMpXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hEZXNjcmlwdGlvbjogXCJSb3cgd2l0aCAzIGNvbHVtbnMuXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBMYXlvdXRFZGl0b3IuQ29sdW1uLnRpbWVzKDMpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTGF5b3V0RWRpdG9yLlJvdy5mcm9tKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveEljb246IFwiXFx1ZjBjOVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94TGFiZWw6IFwiUm93ICg0IGNvbHVtbnMpXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hEZXNjcmlwdGlvbjogXCJSb3cgd2l0aCA0IGNvbHVtbnMuXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBMYXlvdXRFZGl0b3IuQ29sdW1uLnRpbWVzKDQpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTGF5b3V0RWRpdG9yLlJvdy5mcm9tKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveEljb246IFwiXFx1ZjBjOVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94TGFiZWw6IFwiUm93ICg2IGNvbHVtbnMpXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hEZXNjcmlwdGlvbjogXCJSb3cgd2l0aCA2IGNvbHVtbnMuXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBMYXlvdXRFZGl0b3IuQ29sdW1uLnRpbWVzKDYpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTGF5b3V0RWRpdG9yLlJvdy5mcm9tKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveEljb246IFwiXFx1ZjBjOVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94TGFiZWw6IFwiUm93ICgxMiBjb2x1bW5zKVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94RGVzY3JpcHRpb246IFwiUm93IHdpdGggMTIgY29sdW1ucy5cIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW46IExheW91dEVkaXRvci5Db2x1bW4udGltZXMoMTIpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSksIExheW91dEVkaXRvci5Sb3cuZnJvbSh7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hJY29uOiBcIlxcdWYwYzlcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveExhYmVsOiBcIlJvdyAoZW1wdHkpXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hEZXNjcmlwdGlvbjogXCJFbXB0eSByb3cuXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBbXVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5jb2x1bW5FbGVtZW50cyA9IFtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMYXlvdXRFZGl0b3IuQ29sdW1uLmZyb20oe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94SWNvbjogXCJcXHVmMGRiXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hMYWJlbDogXCJDb2x1bW5cIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveERlc2NyaXB0aW9uOiBcIkVtcHR5IGNvbHVtbi5cIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg6IDEsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9mZnNldDogMCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW46IFtdXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIF07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmNhbnZhc0VsZW1lbnRzID0gW1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExheW91dEVkaXRvci5DYW52YXMuZnJvbSh7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hJY29uOiBcIlxcdWYwNDRcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveExhYmVsOiBcIkNhbnZhc1wiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94RGVzY3JpcHRpb246IFwiRW1wdHkgY2FudmFzLlwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogW11cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuY29udGVudEVsZW1lbnRDYXRlZ29yaWVzID0gXygkc2NvcGUuZWxlbWVudC5jb25maWcuY2F0ZWdvcmllcykubWFwKGZ1bmN0aW9uIChjYXRlZ29yeSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU6IGNhdGVnb3J5Lm5hbWUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnRzOiBfKGNhdGVnb3J5LmNvbnRlbnRUeXBlcykubWFwKGZ1bmN0aW9uIChjb250ZW50VHlwZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHR5cGUgPSBjb250ZW50VHlwZS50eXBlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZhY3RvcnkgPSBMYXlvdXRFZGl0b3IuZmFjdG9yaWVzW3R5cGVdIHx8IExheW91dEVkaXRvci5mYWN0b3JpZXNbXCJDb250ZW50XCJdO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGl0ZW0gPSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNUZW1wbGF0ZWQ6IGZhbHNlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRlbnRUeXBlOiBjb250ZW50VHlwZS5pZCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250ZW50VHlwZUxhYmVsOiBjb250ZW50VHlwZS5sYWJlbCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250ZW50VHlwZUNsYXNzOiBjb250ZW50VHlwZS50eXBlQ2xhc3MsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YTogbnVsbCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYXNFZGl0b3I6IGNvbnRlbnRUeXBlLmhhc0VkaXRvcixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBodG1sOiBjb250ZW50VHlwZS5odG1sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGVsZW1lbnQgPSBmYWN0b3J5KGl0ZW0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC50b29sYm94SWNvbiA9IGNvbnRlbnRUeXBlLmljb24gfHwgXCJcXHVmMWM5XCI7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LnRvb2xib3hMYWJlbCA9IGNvbnRlbnRUeXBlLmxhYmVsO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC50b29sYm94RGVzY3JpcHRpb24gPSBjb250ZW50VHlwZS5kZXNjcmlwdGlvbjtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBlbGVtZW50O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUucmVzZXRFbGVtZW50cygpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmdldFNvcnRhYmxlT3B0aW9ucyA9IGZ1bmN0aW9uICh0eXBlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgZWRpdG9ySWQgPSAkZWxlbWVudC5jbG9zZXN0KFwiLmxheW91dC1lZGl0b3JcIikuYXR0cihcImlkXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHBhcmVudENsYXNzZXM7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcGxhY2Vob2xkZXJDbGFzc2VzO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZsb2F0aW5nID0gZmFsc2U7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3dpdGNoICh0eXBlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcIkdyaWRcIjpcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50Q2xhc3NlcyA9IFtcIi5sYXlvdXQtY2FudmFzXCIsIFwiLmxheW91dC1jb2x1bW5cIiwgXCIubGF5b3V0LWNvbW1vbi1ob2xkZXJcIl07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyQ2xhc3NlcyA9IFwibGF5b3V0LWVsZW1lbnQgbGF5b3V0LWNvbnRhaW5lciBsYXlvdXQtZ3JpZCB1aS1zb3J0YWJsZS1wbGFjZWhvbGRlclwiO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwiUm93XCI6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmVudENsYXNzZXMgPSBbXCIubGF5b3V0LWdyaWRcIl07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyQ2xhc3NlcyA9IFwibGF5b3V0LWVsZW1lbnQgbGF5b3V0LWNvbnRhaW5lciBsYXlvdXQtcm93IHJvdyB1aS1zb3J0YWJsZS1wbGFjZWhvbGRlclwiO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwiQ29sdW1uXCI6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmVudENsYXNzZXMgPSBbXCIubGF5b3V0LXJvdzpub3QoLmxheW91dC1yb3ctZnVsbClcIl07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyQ2xhc3NlcyA9IFwibGF5b3V0LWVsZW1lbnQgbGF5b3V0LWNvbnRhaW5lciBsYXlvdXQtY29sdW1uIHVpLXNvcnRhYmxlLXBsYWNlaG9sZGVyXCI7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZsb2F0aW5nID0gdHJ1ZTsgLy8gVG8gZW5zdXJlIGEgc21vb3RoIGhvcml6b250YWwtbGlzdCByZW9yZGVyaW5nLiBodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci11aS91aS1zb3J0YWJsZSNmbG9hdGluZ1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwiQ29udGVudFwiOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRDbGFzc2VzID0gW1wiLmxheW91dC1jYW52YXNcIiwgXCIubGF5b3V0LWNvbHVtblwiLCBcIi5sYXlvdXQtY29tbW9uLWhvbGRlclwiXTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXJDbGFzc2VzID0gXCJsYXlvdXQtZWxlbWVudCBsYXlvdXQtY29udGVudCB1aS1zb3J0YWJsZS1wbGFjZWhvbGRlclwiO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwiQ2FudmFzXCI6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmVudENsYXNzZXMgPSBbXCIubGF5b3V0LWNhbnZhc1wiLCBcIi5sYXlvdXQtY29sdW1uXCIsIFwiLmxheW91dC1jb21tb24taG9sZGVyXCJdO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlckNsYXNzZXMgPSBcImxheW91dC1lbGVtZW50IGxheW91dC1jb250YWluZXIgbGF5b3V0LWdyaWQgdWktc29ydGFibGUtcGxhY2Vob2xkZXJcIjtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJzb3I6IFwibW92ZVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3RXaXRoOiBfKHBhcmVudENsYXNzZXMpLm1hcChmdW5jdGlvbiAoZSkgeyByZXR1cm4gXCIjXCIgKyBlZGl0b3JJZCArIFwiIFwiICsgZSArIFwiOm5vdCgubGF5b3V0LWNvbnRhaW5lci1zZWFsZWQpID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNoaWxkcmVuXCI7IH0pLmpvaW4oXCIsIFwiKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlcjogcGxhY2Vob2xkZXJDbGFzc2VzLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwidWktZmxvYXRpbmdcIjogZmxvYXRpbmcsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAoZSwgdWkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZS50YXJnZXQuaXNUb29sYm94ID0gdHJ1ZTsgLy8gV2lsbCBpbmRpY2F0ZSB0byBjb25uZWN0ZWQgc29ydGFibGVzIHRoYXQgZHJvcHBlZCBpdGVtcyB3ZXJlIHNlbnQgZnJvbSB0b29sYm94LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQ6IGZ1bmN0aW9uIChlLCB1aSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuJGFwcGx5KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5lbGVtZW50LmlzRHJhZ2dpbmcgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0b3A6IGZ1bmN0aW9uIChlLCB1aSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuJGFwcGx5KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5lbGVtZW50LmlzRHJhZ2dpbmcgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5yZXNldEVsZW1lbnRzKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3ZlcjogZnVuY3Rpb24gKGUsIHVpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kYXBwbHkoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmVsZW1lbnQuY2FudmFzLnNldElzRHJvcFRhcmdldChmYWxzZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgbGF5b3V0SXNDb2xsYXBzZWRDb29raWVOYW1lID0gXCJsYXlvdXRUb29sYm94Q2F0ZWdvcnlfTGF5b3V0X0lzQ29sbGFwc2VkXCI7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5sYXlvdXRJc0NvbGxhcHNlZCA9ICQuY29va2llKGxheW91dElzQ29sbGFwc2VkQ29va2llTmFtZSkgPT09IFwidHJ1ZVwiO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLnRvZ2dsZUxheW91dElzQ29sbGFwc2VkID0gZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5sYXlvdXRJc0NvbGxhcHNlZCA9ICEkc2NvcGUubGF5b3V0SXNDb2xsYXBzZWQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmNvb2tpZShsYXlvdXRJc0NvbGxhcHNlZENvb2tpZU5hbWUsICRzY29wZS5sYXlvdXRJc0NvbGxhcHNlZCwgeyBleHBpcmVzOiAzNjUgfSk7IC8vIFJlbWVtYmVyIGNvbGxhcHNlZCBzdGF0ZSBmb3IgYSB5ZWFyLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBdLFxyXG4gICAgICAgICAgICAgICAgdGVtcGxhdGVVcmw6IGVudmlyb25tZW50LnRlbXBsYXRlVXJsKFwiVG9vbGJveFwiKSxcclxuICAgICAgICAgICAgICAgIHJlcGxhY2U6IHRydWUsXHJcbiAgICAgICAgICAgICAgICBsaW5rOiBmdW5jdGlvbiAoc2NvcGUsIGVsZW1lbnQpIHtcclxuICAgICAgICAgICAgICAgICAgICB2YXIgdG9vbGJveCA9IGVsZW1lbnQuZmluZChcIi5sYXlvdXQtdG9vbGJveFwiKTtcclxuICAgICAgICAgICAgICAgICAgICAkKHdpbmRvdykub24oXCJyZXNpemUgc2Nyb2xsXCIsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBjYW52YXMgPSBlbGVtZW50LnBhcmVudCgpLmZpbmQoXCIubGF5b3V0LWNhbnZhc1wiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhlIGNhbnZhcyBpcyB0YWxsZXIgdGhhbiB0aGUgdG9vbGJveCwgbWFrZSB0aGUgdG9vbGJveCBzdGlja3ktcG9zaXRpb25lZCB3aXRoaW4gdGhlIGVkaXRvclxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB0byBoZWxwIHRoZSB1c2VyIGF2b2lkIGV4Y2Vzc2l2ZSB2ZXJ0aWNhbCBzY3JvbGxpbmcuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBjYW52YXNJc1RhbGxlciA9ICEhY2FudmFzICYmIGNhbnZhcy5oZWlnaHQoKSA+IHRvb2xib3guaGVpZ2h0KCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciB3aW5kb3dQb3MgPSAkKHdpbmRvdykuc2Nyb2xsVG9wKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjYW52YXNJc1RhbGxlciAmJiB3aW5kb3dQb3MgPiBlbGVtZW50Lm9mZnNldCgpLnRvcCArIGVsZW1lbnQuaGVpZ2h0KCkgLSB0b29sYm94LmhlaWdodCgpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94LmFkZENsYXNzKFwic3RpY2t5LWJvdHRvbVwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3gucmVtb3ZlQ2xhc3MoXCJzdGlja3ktdG9wXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKGNhbnZhc0lzVGFsbGVyICYmIHdpbmRvd1BvcyA+IGVsZW1lbnQub2Zmc2V0KCkudG9wKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94LmFkZENsYXNzKFwic3RpY2t5LXRvcFwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3gucmVtb3ZlQ2xhc3MoXCJzdGlja3ktYm90dG9tXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveC5yZW1vdmVDbGFzcyhcInN0aWNreS10b3BcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94LnJlbW92ZUNsYXNzKFwic3RpY2t5LWJvdHRvbVwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9O1xyXG4gICAgICAgIH1cclxuICAgIF0pOyIsImFuZ3VsYXJcclxuICAgIC5tb2R1bGUoXCJMYXlvdXRFZGl0b3JcIilcclxuICAgIC5kaXJlY3RpdmUoXCJvcmNMYXlvdXRUb29sYm94R3JvdXBcIiwgW1wiJGNvbXBpbGVcIiwgXCJlbnZpcm9ubWVudFwiLFxyXG4gICAgICAgIGZ1bmN0aW9uICgkY29tcGlsZSwgZW52aXJvbm1lbnQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICAgIHJlc3RyaWN0OiBcIkVcIixcclxuICAgICAgICAgICAgICAgIHNjb3BlOiB7IGNhdGVnb3J5OiBcIj1cIiB9LFxyXG4gICAgICAgICAgICAgICAgY29udHJvbGxlcjogW1wiJHNjb3BlXCIsIFwiJGVsZW1lbnRcIixcclxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoJHNjb3BlLCAkZWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNDb2xsYXBzZWRDb29raWVOYW1lID0gXCJsYXlvdXRUb29sYm94Q2F0ZWdvcnlfXCIgKyAkc2NvcGUuY2F0ZWdvcnkubmFtZSArIFwiX0lzQ29sbGFwc2VkXCI7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5pc0NvbGxhcHNlZCA9ICQuY29va2llKGlzQ29sbGFwc2VkQ29va2llTmFtZSkgPT09IFwidHJ1ZVwiO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUudG9nZ2xlSXNDb2xsYXBzZWQgPSBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmlzQ29sbGFwc2VkID0gISRzY29wZS5pc0NvbGxhcHNlZDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuY29va2llKGlzQ29sbGFwc2VkQ29va2llTmFtZSwgJHNjb3BlLmlzQ29sbGFwc2VkLCB7IGV4cGlyZXM6IDM2NSB9KTsgLy8gUmVtZW1iZXIgY29sbGFwc2VkIHN0YXRlIGZvciBhIHllYXIuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIF0sXHJcbiAgICAgICAgICAgICAgICB0ZW1wbGF0ZVVybDogZW52aXJvbm1lbnQudGVtcGxhdGVVcmwoXCJUb29sYm94R3JvdXBcIiksXHJcbiAgICAgICAgICAgICAgICByZXBsYWNlOiB0cnVlXHJcbiAgICAgICAgICAgIH07XHJcbiAgICAgICAgfVxyXG4gICAgXSk7Il19 +//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L0xheW91dEVkaXRvci9Nb2R1bGUuanMiLCJPcmNoYXJkLldlYi9Nb2R1bGVzL09yY2hhcmQuTGF5b3V0cy9Bc3NldHMvSmF2YVNjcmlwdC9MYXlvdXRFZGl0b3IvU2VydmljZXMvQ2xpcGJvYXJkLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTGF5b3V0RWRpdG9yL1NlcnZpY2VzL1Njb3BlQ29uZmlndXJhdG9yLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTGF5b3V0RWRpdG9yL0RpcmVjdGl2ZXMvRWRpdG9yLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTGF5b3V0RWRpdG9yL0RpcmVjdGl2ZXMvQ2FudmFzLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTGF5b3V0RWRpdG9yL0RpcmVjdGl2ZXMvQ2hpbGQuanMiLCJPcmNoYXJkLldlYi9Nb2R1bGVzL09yY2hhcmQuTGF5b3V0cy9Bc3NldHMvSmF2YVNjcmlwdC9MYXlvdXRFZGl0b3IvRGlyZWN0aXZlcy9Db2x1bW4uanMiLCJPcmNoYXJkLldlYi9Nb2R1bGVzL09yY2hhcmQuTGF5b3V0cy9Bc3NldHMvSmF2YVNjcmlwdC9MYXlvdXRFZGl0b3IvRGlyZWN0aXZlcy9Db250ZW50LmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTGF5b3V0RWRpdG9yL0RpcmVjdGl2ZXMvR3JpZC5qcyIsIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L0xheW91dEVkaXRvci9EaXJlY3RpdmVzL1Jvdy5qcyIsIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L0xheW91dEVkaXRvci9EaXJlY3RpdmVzL1BvcHVwLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTGF5b3V0RWRpdG9yL0RpcmVjdGl2ZXMvVG9vbGJveC5qcyIsIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L0xheW91dEVkaXRvci9EaXJlY3RpdmVzL1Rvb2xib3hHcm91cC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLE9BQU8sQ0FBQyxNQUFNLENBQUMsY0FBYyxFQUFFLENBQUMsWUFBWSxFQUFFLFlBQVksRUFBRSxhQUFhLENBQUMsQ0FBQyxDQUFDO0FDQTVFLElBQUksWUFBWSxDQUFDO0FBQ2pCLENBQUMsVUFBUyxZQUFZO0lBRWxCLElBQUksU0FBUyxHQUFHO1FBQ1osSUFBSSxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2hCLElBQUksQ0FBQyxjQUFjLEdBQUcsRUFBRSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDO1FBQ3pCLElBQUksQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDO1FBRXpCLElBQUksQ0FBQyxPQUFPLEdBQUcsVUFBUyxXQUFXLEVBQUUsSUFBSTtZQUNyQyxJQUFJLENBQUMsY0FBYyxDQUFDLFdBQVcsQ0FBQyxHQUFHLElBQUksQ0FBQztZQUN4QyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztRQUM1QixDQUFDLENBQUM7UUFDRixJQUFJLENBQUMsT0FBTyxHQUFHLFVBQVUsV0FBVztZQUNoQyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztZQUN4QixNQUFNLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUM1QyxDQUFDLENBQUM7UUFDRixJQUFJLENBQUMsT0FBTyxHQUFHO1lBQ1gsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7WUFDeEIsSUFBSSxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUM7WUFDekIsSUFBSSxDQUFDLGNBQWMsR0FBRyxFQUFFLENBQUM7UUFDN0IsQ0FBQyxDQUFDO1FBQ0YsSUFBSSxDQUFDLFVBQVUsR0FBRztZQUNkLE1BQU0sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDO1FBQzVCLENBQUMsQ0FBQTtRQUNELElBQUksQ0FBQyxVQUFVLEdBQUc7WUFDZCxNQUFNLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQztRQUM1QixDQUFDLENBQUE7SUFDTCxDQUFDLENBQUE7SUFFRCxZQUFZLENBQUMsU0FBUyxHQUFHLElBQUksU0FBUyxFQUFFLENBQUM7SUFFekMsT0FBTztTQUNGLE1BQU0sQ0FBQyxjQUFjLENBQUM7U0FDdEIsT0FBTyxDQUFDLFdBQVcsRUFBRTtRQUNsQjtZQUNJLE1BQU0sQ0FBQztnQkFDSCxPQUFPLEVBQUUsWUFBWSxDQUFDLFNBQVMsQ0FBQyxPQUFPO2dCQUN2QyxPQUFPLEVBQUUsWUFBWSxDQUFDLFNBQVMsQ0FBQyxPQUFPO2dCQUN2QyxPQUFPLEVBQUUsWUFBWSxDQUFDLFNBQVMsQ0FBQyxPQUFPO2dCQUN2QyxVQUFVLEVBQUUsWUFBWSxDQUFDLFNBQVMsQ0FBQyxVQUFVO2dCQUM3QyxVQUFVLEVBQUUsWUFBWSxDQUFDLFNBQVMsQ0FBQyxVQUFVO2FBQ2hELENBQUM7UUFDTixDQUFDO0tBQ0osQ0FBQyxDQUFDO0FBQ1gsQ0FBQyxDQUFDLENBQUMsWUFBWSxJQUFJLENBQUMsWUFBWSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUM3Q3hDLE9BQU87S0FDRixNQUFNLENBQUMsY0FBYyxDQUFDO0tBQ3RCLE9BQU8sQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLFVBQVUsRUFBRSxXQUFXO0lBQ2xELFVBQVUsUUFBUSxFQUFFLFNBQVM7UUFDekIsTUFBTSxDQUFDO1lBRUgsbUJBQW1CLEVBQUUsVUFBVSxNQUFNLEVBQUUsUUFBUTtnQkFFM0MsUUFBUSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDO29CQUM1QyxDQUFDLENBQUMsZUFBZSxFQUFFLENBQUM7Z0JBQ3hCLENBQUMsQ0FBQyxDQUFDO2dCQUVILFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDO29CQUNqQyxJQUFJLE9BQU8sR0FBRyxLQUFLLENBQUM7b0JBQ3BCLElBQUksVUFBVSxHQUFHLEtBQUssQ0FBQztvQkFDdkIsSUFBSSxPQUFPLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQztvQkFFN0IsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUM7d0JBQzFCLE1BQU0sQ0FBQztvQkFFWCxvRkFBb0Y7b0JBQ3BGLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQzt3QkFDMUIsSUFBSSxjQUFjLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUM7d0JBQ25ELEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDOzRCQUNuQixpRkFBaUY7NEJBQ2pGLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO2dDQUNaLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO29DQUNsQixLQUFLLEVBQUU7d0NBQ0gsY0FBYyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQzt3Q0FDL0IsS0FBSyxDQUFDO29DQUNWLEtBQUssRUFBRTt3Q0FDSCxjQUFjLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO3dDQUM5QixLQUFLLENBQUM7b0NBQ1YsS0FBSyxFQUFFO3dDQUNILGNBQWMsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7d0NBQ2hDLEtBQUssQ0FBQztnQ0FDVixDQUFDOzRCQUNMLENBQUM7d0JBQ0wsQ0FBQztvQkFDTCxDQUFDO29CQUVELEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxRQUFRLElBQUksQ0FBQyxDQUFDLENBQUMsTUFBTSxJQUFJLENBQUMsQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQzt3QkFDMUQsTUFBTSxDQUFDLFFBQU0sQ0FBQSxDQUFDLE9BQU8sQ0FBQyxDQUFDO3dCQUN2QixPQUFPLEdBQUcsSUFBSSxDQUFDO29CQUNuQixDQUFDO29CQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO3dCQUNwRixRQUFRLENBQUMsSUFBSSxDQUFDLGlDQUFpQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUM7d0JBQ2pFLE9BQU8sR0FBRyxJQUFJLENBQUM7b0JBQ25CLENBQUM7b0JBRUQsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO3dCQUN0QixFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBSSxDQUFDLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7NEJBQzFELFFBQVEsQ0FBQyxJQUFJLENBQUMsMkJBQTJCLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxLQUFLLEVBQUUsQ0FBQzs0QkFDM0QsT0FBTyxHQUFHLElBQUksQ0FBQzt3QkFDbkIsQ0FBQztvQkFDTCxDQUFDO29CQUVELEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQzt3QkFDckIsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBSSxDQUFDLENBQUMsTUFBTSxJQUFJLENBQUMsQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQzs0QkFDekQsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO2dDQUM1QixPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLFlBQVksRUFBRSxDQUFDOzRCQUN2QyxPQUFPLEdBQUcsSUFBSSxDQUFDO3dCQUNuQixDQUFDO3dCQUVELEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLElBQUksUUFBUSxDQUFDLENBQUMsQ0FBQzs0QkFDM0IsSUFBSSxlQUFlLEdBQUcsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDOzRCQUNqQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7Z0NBQ2hCLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7b0NBQ1QsT0FBTyxDQUFDLFVBQVUsQ0FBQyxlQUFlLENBQUMsQ0FBQztnQ0FDeEMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQztvQ0FDWCxPQUFPLENBQUMsYUFBYSxDQUFDLGVBQWUsQ0FBQyxDQUFDO2dDQUMzQyxPQUFPLEdBQUcsSUFBSSxDQUFDOzRCQUNuQixDQUFDOzRCQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7Z0NBQ3ZCLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7b0NBQ1QsT0FBTyxDQUFDLFlBQVksQ0FBQyxlQUFlLENBQUMsQ0FBQztnQ0FDMUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQztvQ0FDWCxPQUFPLENBQUMsV0FBVyxDQUFDLGVBQWUsQ0FBQyxDQUFDO2dDQUN6QyxPQUFPLEdBQUcsSUFBSSxDQUFDOzRCQUNuQixDQUFDO3dCQUNMLENBQUM7b0JBQ0wsQ0FBQztvQkFFRCxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7d0JBQ25CLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDOzRCQUM1QixPQUFPLENBQUMsTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDOzRCQUM5QixPQUFPLEdBQUcsSUFBSSxDQUFDO3dCQUNuQixDQUFDO3dCQUVELEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUM7NEJBQy9CLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxRQUFRLElBQUksQ0FBQyxDQUFDLENBQUMsTUFBTSxJQUFJLENBQUMsQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztnQ0FDMUQsT0FBTyxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQ0FDM0MsT0FBTyxHQUFHLElBQUksQ0FBQzs0QkFDbkIsQ0FBQzs0QkFDRCxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO2dDQUMvRCxPQUFPLENBQUMsTUFBTSxDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxDQUFDO2dDQUMzQyxPQUFPLEdBQUcsSUFBSSxDQUFDOzRCQUNuQixDQUFDOzRCQUNELElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO2dDQUM5RCxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7Z0NBQ2pCLFVBQVUsR0FBRyxJQUFJLENBQUM7Z0NBQ2xCLE9BQU8sR0FBRyxJQUFJLENBQUM7NEJBQ25CLENBQUM7NEJBQ0QsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBSSxDQUFDLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7Z0NBQzlELE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQztnQ0FDbkIsT0FBTyxHQUFHLElBQUksQ0FBQzs0QkFDbkIsQ0FBQzt3QkFDTCxDQUFDO3dCQUNELElBQUksQ0FBQyxDQUFDOzRCQUNGLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxRQUFRLElBQUksQ0FBQyxDQUFDLENBQUMsTUFBTSxJQUFJLENBQUMsQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztnQ0FDMUQsT0FBTyxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQ0FDM0MsT0FBTyxHQUFHLElBQUksQ0FBQzs0QkFDbkIsQ0FBQzs0QkFDRCxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO2dDQUMvRCxPQUFPLENBQUMsTUFBTSxDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxDQUFDO2dDQUMzQyxPQUFPLEdBQUcsSUFBSSxDQUFDOzRCQUNuQixDQUFDOzRCQUNELElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO2dDQUM5RCxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7Z0NBQ2pCLFVBQVUsR0FBRyxJQUFJLENBQUM7Z0NBQ2xCLE9BQU8sR0FBRyxJQUFJLENBQUM7NEJBQ25CLENBQUM7NEJBQ0QsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBSSxDQUFDLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7Z0NBQzlELE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQztnQ0FDbkIsT0FBTyxHQUFHLElBQUksQ0FBQzs0QkFDbkIsQ0FBQzt3QkFDTCxDQUFDO29CQUNMLENBQUM7b0JBRUQsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQzt3QkFDVixDQUFDLENBQUMsY0FBYyxFQUFFLENBQUM7b0JBQ3ZCLENBQUM7b0JBRUQsQ0FBQyxDQUFDLGVBQWUsRUFBRSxDQUFDO29CQUVwQixNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxnRkFBZ0Y7b0JBRWpHLDJIQUEySDtvQkFDM0gsRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQzt3QkFDYixNQUFNLENBQUMsVUFBVSxDQUFDOzRCQUNkLE1BQU0sQ0FBQyxNQUFNLENBQUM7Z0NBQ1YsT0FBTyxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsWUFBWSxFQUFFLENBQUM7NEJBQ2pELENBQUMsQ0FBQyxDQUFDO3dCQUNQLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztvQkFDWixDQUFDO2dCQUNMLENBQUMsQ0FBQyxDQUFDO2dCQUVILE1BQU0sQ0FBQyxPQUFPLENBQUMseUJBQXlCLENBQUMsSUFBSSxDQUFDO29CQUMxQyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQzlCLENBQUMsQ0FBQyxDQUFDO2dCQUVILE1BQU0sQ0FBQyxRQUFNLENBQUEsR0FBRyxVQUFVLE9BQU87b0JBQzdCLE9BQU8sQ0FBQyxRQUFNLENBQUEsRUFBRSxDQUFDO29CQUNqQixDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQzt3QkFDWixJQUFJLEVBQUUscUJBQXFCO3FCQUM5QixDQUFDLENBQUM7Z0JBQ1AsQ0FBQyxDQUFBO2dCQUVELEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQztvQkFDM0IsTUFBTSxDQUFDLElBQUksR0FBRzt3QkFDVixNQUFNLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsSUFBSTs0QkFDeEQsTUFBTSxDQUFDLE1BQU0sQ0FBQztnQ0FDVixFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO29DQUNaLE1BQU0sQ0FBQztnQ0FFWCxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQztnQ0FDeEMsTUFBTSxDQUFDLE9BQU8sQ0FBQyx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsQ0FBQztnQ0FFaEUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDO29DQUN6QixNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDOzRCQUNsRCxDQUFDLENBQUMsQ0FBQzt3QkFDUCxDQUFDLENBQUMsQ0FBQztvQkFDUCxDQUFDLENBQUM7Z0JBQ04sQ0FBQztZQUNMLENBQUM7WUFFRCxxQkFBcUIsRUFBRSxVQUFVLE1BQU0sRUFBRSxRQUFRO2dCQUM3QyxJQUFJLE9BQU8sR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDO2dCQUU3QixvR0FBb0c7Z0JBQ3BHLE1BQU0sQ0FBQywwQkFBMEIsR0FBRztvQkFDaEMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLGVBQWUsRUFBRSxDQUFDO2dCQUNyRixDQUFDLENBQUM7Z0JBRUYsTUFBTSxDQUFDLGVBQWUsR0FBRztvQkFDckIsTUFBTSxFQUFFLE1BQU07b0JBQ2QsS0FBSyxFQUFFLEdBQUc7b0JBQ1YsUUFBUSxFQUFFLE9BQU8sQ0FBQyxXQUFXLEVBQUU7b0JBQy9CLFFBQVEsRUFBRSxDQUFDO29CQUNYLDJJQUEySTtvQkFDM0ksS0FBSyxFQUFFLFVBQVUsQ0FBQyxFQUFFLEVBQUU7d0JBQ2xCLE1BQU0sQ0FBQyxNQUFNLENBQUM7NEJBQ1YsT0FBTyxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQzs0QkFDOUIsT0FBTyxDQUFDLE1BQU0sQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDO3dCQUNyQyxDQUFDLENBQUMsQ0FBQzt3QkFDSCxzRUFBc0U7d0JBQ3RFLEVBQUUsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7d0JBQzVDLEVBQUUsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDLENBQUMsQ0FBQztvQkFDeEMsQ0FBQztvQkFDRCxJQUFJLEVBQUUsVUFBVSxDQUFDLEVBQUUsRUFBRTt3QkFDakIsTUFBTSxDQUFDLE1BQU0sQ0FBQzs0QkFDVixPQUFPLENBQUMsTUFBTSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUM7NEJBQ2xDLE9BQU8sQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUM7d0JBQ25DLENBQUMsQ0FBQyxDQUFDO29CQUNQLENBQUM7b0JBQ0QsSUFBSSxFQUFFLFVBQVUsQ0FBQyxFQUFFLEVBQUU7d0JBQ2pCLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsTUFBTSxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7NEJBQzFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLGlCQUFpQixDQUFDLENBQUMsQ0FBQztnQ0FDbkMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLGlCQUFpQixDQUFDLENBQUM7Z0NBQ2hELEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxDQUFDOzRCQUMxQyxDQUFDOzRCQUNELFFBQVEsQ0FBQztnQ0FDTCxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUM7b0NBQ3hCLGlHQUFpRztvQ0FDakcsSUFBSSxrQkFBa0IsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDO29DQUMxRCxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsa0JBQWtCLElBQUksa0JBQWtCLENBQUMsSUFBSSxJQUFJLEtBQUssQ0FBQzt3Q0FDekQsa0JBQWtCLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztnQ0FDL0MsQ0FBQztnQ0FDRCxPQUFPLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDOzRCQUNuQyxDQUFDLENBQUMsQ0FBQzs0QkFDSCxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLGlCQUFpQixHQUFHLFFBQVEsQ0FBQztnQ0FDdEMsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDO29DQUN4QixJQUFJLGNBQWMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUM7b0NBQzVDLElBQUksbUJBQW1CLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLEdBQUcsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO29DQUN6RSxjQUFjLENBQUMsS0FBSyxHQUFHLG1CQUFtQixDQUFDO29DQUMzQyxjQUFjLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztvQ0FDMUIsT0FBTyxDQUFDLGNBQWMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO29DQUM1Qyw0R0FBNEc7b0NBQzVHLElBQUksU0FBUyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsbUVBQW1FLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUM7d0NBQ3ZILE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUM7b0NBQ3pCLENBQUMsQ0FBQyxDQUFDLENBQUM7b0NBQ0osR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsRUFBRTt3Q0FDcEIsRUFBRSxDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUMsU0FBUyxHQUFHLENBQUMsQ0FBQyxDQUFDO29DQUM5QyxFQUFFLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxTQUFTLEdBQUcsY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFDO29DQUMxRCxFQUFFLENBQUMsQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQzt3Q0FDaEIsRUFBRSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUM7d0NBQ2pDLEVBQUUsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDLENBQUMsQ0FBQztvQ0FDeEMsQ0FBQztvQ0FDRCxJQUFJLENBQUMsQ0FBQzt3Q0FDRixFQUFFLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQzt3Q0FDekIsRUFBRSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQyxDQUFDO29DQUN6QyxDQUFDO2dDQUNMLENBQUM7Z0NBQ0QsT0FBTyxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQzs0QkFDbEMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO3dCQUNaLENBQUM7b0JBQ0wsQ0FBQztvQkFDRCxPQUFPLEVBQUUsVUFBVSxDQUFDLEVBQUUsRUFBRTt3QkFDcEIsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQzs0QkFDMUMsTUFBTSxDQUFDLE1BQU0sQ0FBQztnQ0FDVixJQUFJLGVBQWUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUM7Z0NBQzdDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDO29DQUNwQixFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxJQUFJLEtBQUssQ0FBQzt3Q0FDdEIsT0FBTyxDQUFDLGVBQWUsRUFBRSxDQUFDO29DQUM5Qix3RkFBd0Y7b0NBQ3hGLHlGQUF5RjtvQ0FDekYsdUVBQXVFO29DQUN2RSwrSEFBK0g7b0NBQy9ILGVBQWUsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO29DQUMxQyxlQUFlLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDO29DQUVuQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7d0NBQzlCLE1BQU0sQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLGVBQWUsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLElBQUk7NENBQ3pELEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7Z0RBQ2YsZUFBZSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQztnREFDekMsZUFBZSxDQUFDLHVCQUF1QixDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO2dEQUVqRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQztvREFDMUIsZUFBZSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDOzRDQUNuRCxDQUFDOzRDQUNELFFBQVEsQ0FBQztnREFDTCxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQztvREFDZCxlQUFlLENBQUMsUUFBTSxDQUFBLEVBQUUsQ0FBQztnREFDN0IsSUFBSTtvREFDQSxlQUFlLENBQUMsWUFBWSxFQUFFLENBQUM7Z0RBQ25DLDZCQUE2QjtnREFDN0IsT0FBTyxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQzs0Q0FFbkMsQ0FBQyxDQUFDLENBQUM7NENBQ0gsTUFBTSxDQUFDO3dDQUNYLENBQUMsQ0FBQyxDQUFDO29DQUNQLENBQUM7Z0NBQ0wsQ0FBQztnQ0FDRCxRQUFRLENBQUM7b0NBQ0wsNkJBQTZCO29DQUM3QixPQUFPLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDO29DQUMvQixFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsZUFBZSxDQUFDO3dDQUNsQixlQUFlLENBQUMsWUFBWSxFQUFFLENBQUM7b0NBRW5DLE1BQU0sQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLGVBQWUsQ0FBQyxDQUFDLElBQUksQ0FBQzt3Q0FDMUMsTUFBTSxDQUFDO29DQUNYLENBQUMsQ0FBQyxDQUFDO2dDQUNQLENBQUMsQ0FBQyxDQUFDOzRCQUNQLENBQUMsQ0FBQyxDQUFDO3dCQUNQLENBQUM7b0JBQ0wsQ0FBQztpQkFDSixDQUFDO2dCQUVGLE1BQU0sQ0FBQyxLQUFLLEdBQUcsVUFBVSxLQUFLLEVBQUUsQ0FBQztvQkFDN0IsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQzt3QkFDekIsS0FBSyxDQUFDLFlBQVksRUFBRSxDQUFDO29CQUN6QixDQUFDLENBQUMsZUFBZSxFQUFFLENBQUM7Z0JBQ3hCLENBQUMsQ0FBQztnQkFFRixNQUFNLENBQUMsVUFBVSxHQUFHLFVBQVUsS0FBSztvQkFDL0IsSUFBSSxNQUFNLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO29CQUVoQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7d0JBQ25CLE1BQU0sQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsQ0FBQzt3QkFDaEMsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDOzRCQUNwQixNQUFNLENBQUMsSUFBSSxDQUFDLHlCQUF5QixDQUFDLENBQUM7b0JBQy9DLENBQUM7b0JBRUQsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO29CQUVsRCxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQzt3QkFDeEIsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUM7b0JBRXZDLDZFQUE2RTtvQkFDN0UsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDO3dCQUN0QixNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO3dCQUNuQixFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQUUsQ0FBQzs0QkFDdEIsTUFBTSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO29CQUN2QyxDQUFDO29CQUNELEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLElBQUksUUFBUSxDQUFDLENBQUMsQ0FBQzt3QkFDekIsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO3dCQUNyQyxNQUFNLENBQUMsSUFBSSxDQUFDLGdCQUFnQixHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztvQkFDakQsQ0FBQztvQkFDRCxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxJQUFJLFNBQVMsQ0FBQzt3QkFDeEIsTUFBTSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxLQUFLLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztvQkFFNUQsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDO3dCQUNwQixNQUFNLENBQUMsSUFBSSxDQUFDLHVCQUF1QixDQUFDLENBQUM7b0JBQ3pDLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQUUsQ0FBQzt3QkFDckIsTUFBTSxDQUFDLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO29CQUMxQyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsYUFBYSxFQUFFLENBQUM7d0JBQ3RCLE1BQU0sQ0FBQyxJQUFJLENBQUMseUJBQXlCLENBQUMsQ0FBQztvQkFDM0MsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDO3dCQUN4QixNQUFNLENBQUMsSUFBSSxDQUFDLDJCQUEyQixDQUFDLENBQUM7b0JBQzdDLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUM7d0JBQ2xCLE1BQU0sQ0FBQyxJQUFJLENBQUMsMEJBQTBCLENBQUMsQ0FBQztvQkFFNUMsTUFBTSxDQUFDLE1BQU0sQ0FBQztnQkFDbEIsQ0FBQyxDQUFDO1lBQ04sQ0FBQztTQUNKLENBQUM7SUFDTixDQUFDO0NBQ0osQ0FBQyxDQUFDO0FDelZQLE9BQU87S0FDRixNQUFNLENBQUMsY0FBYyxDQUFDO0tBQ3RCLFNBQVMsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLGFBQWE7SUFDeEMsVUFBVSxXQUFXO1FBQ2pCLE1BQU0sQ0FBQztZQUNILFFBQVEsRUFBRSxHQUFHO1lBQ2IsS0FBSyxFQUFFLEVBQUU7WUFDVCxVQUFVLEVBQUUsQ0FBQyxRQUFRLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRSxVQUFVLEVBQUUsV0FBVztnQkFDaEUsVUFBVSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsU0FBUztvQkFDbkQsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUM7d0JBQ2YsTUFBTSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO29CQUN4QyxJQUFJO3dCQUNBLE1BQU0sSUFBSSxLQUFLLENBQUMsc0VBQXNFLENBQUMsQ0FBQztvQkFFNUYsTUFBTSxDQUFDLEtBQUssR0FBRyxVQUFVLE1BQU0sRUFBRSxDQUFDO3dCQUM5QixFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDOzRCQUMxQixNQUFNLENBQUMsWUFBWSxFQUFFLENBQUM7d0JBQzFCLENBQUMsQ0FBQyxlQUFlLEVBQUUsQ0FBQztvQkFDeEIsQ0FBQyxDQUFDO29CQUVGLE1BQU0sQ0FBQyxVQUFVLEdBQUcsVUFBVSxNQUFNO3dCQUNoQyxJQUFJLE1BQU0sR0FBRyxDQUFDLGdCQUFnQixFQUFFLGtCQUFrQixFQUFFLGVBQWUsQ0FBQyxDQUFDO3dCQUVyRSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLENBQUM7NEJBQ3JCLE1BQU0sQ0FBQyxJQUFJLENBQUMsdUJBQXVCLENBQUMsQ0FBQzt3QkFDekMsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDOzRCQUN0QixNQUFNLENBQUMsSUFBSSxDQUFDLHdCQUF3QixDQUFDLENBQUM7d0JBQzFDLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxhQUFhLEVBQUUsQ0FBQzs0QkFDdkIsTUFBTSxDQUFDLElBQUksQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO3dCQUMzQyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsZUFBZSxFQUFFLENBQUM7NEJBQ3pCLE1BQU0sQ0FBQyxJQUFJLENBQUMsMkJBQTJCLENBQUMsQ0FBQzt3QkFDN0MsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQzs0QkFDbkIsTUFBTSxDQUFDLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO3dCQUU1QyxNQUFNLENBQUMsTUFBTSxDQUFDO29CQUNsQixDQUFDLENBQUM7b0JBRUYsc0xBQXNMO29CQUN0TCwySEFBMkg7b0JBQzNILGdHQUFnRztvQkFDaEcsSUFBSSxrQkFBa0IsR0FBRyxDQUFDLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsQ0FBQztvQkFFNUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsR0FBRyxrQkFBa0IsQ0FBQztvQkFFckQsa0JBQWtCLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxlQUFlLEVBQUUsVUFBVSxDQUFDLEVBQUUsSUFBSTt3QkFDNUQsSUFBSSxNQUFNLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQzt3QkFDNUIsSUFBSSxVQUFVLEdBQUc7NEJBQ2IsSUFBSSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSTs0QkFDdEIsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTTs0QkFDMUIsU0FBUyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUzs0QkFDaEMsU0FBUyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUzs0QkFDaEMsV0FBVyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVzs0QkFDcEMsUUFBUSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUTt5QkFDakMsQ0FBQzt3QkFFRixrSUFBa0k7d0JBQ2xJLHVKQUF1Sjt3QkFDdkosK0pBQStKO3dCQUMvSixpSEFBaUg7d0JBQ2pILDhMQUE4TDt3QkFDOUwsa0JBQWtCLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxZQUFZLEdBQUcsSUFBSSxZQUFZLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsVUFBVSxDQUFDLENBQUM7d0JBQ3JHLElBQUksUUFBUSxHQUFHLG9CQUFvQixHQUFHLGlDQUFpQyxDQUFDO3dCQUN4RSxJQUFJLElBQUksR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUM7d0JBQ3RDLENBQUMsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDMUMsQ0FBQyxDQUFDLENBQUM7b0JBRUgsTUFBTSxDQUFDLEtBQUssQ0FBQyxXQUFXLEdBQUcsVUFBVSxPQUFPO3dCQUN4QyxJQUFJLElBQUksR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLGtCQUFrQixDQUFDO3dCQUMzQyxNQUFNLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQztvQkFDckMsQ0FBQyxDQUFDO29CQUVGLE1BQU0sQ0FBQyxLQUFLLENBQUMsVUFBVSxHQUFHLFVBQVUsV0FBVzt3QkFDM0MsSUFBSSxJQUFJLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQzt3QkFDM0MsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUM7b0JBQ3hDLENBQUMsQ0FBQztvQkFFRixDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxDQUFDLGdCQUFnQixFQUFFLFVBQVUsQ0FBQzt3QkFDeEMsb0ZBQW9GO3dCQUNwRixtRkFBbUY7d0JBQ25GLHFGQUFxRjt3QkFDckYscURBQXFEO3dCQUNyRCxFQUFFLENBQUMsQ0FBQyxTQUFTLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDOzRCQUN6QixDQUFDLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLFNBQVMsQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQzs0QkFDckYsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxTQUFTLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7NEJBQ25GLENBQUMsQ0FBQyxjQUFjLEVBQUUsQ0FBQzt3QkFDdkIsQ0FBQzt3QkFDRCxJQUFJLENBQUMsQ0FBQzs0QkFDRixJQUFJLGNBQWMsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQzs0QkFDbkQsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUM7Z0NBQ25CLE1BQU0sQ0FBQyxNQUFNLENBQUM7b0NBQ1YsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7d0NBQ2IsS0FBSyxNQUFNOzRDQUNQLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUMsQ0FBQzs0Q0FDbkQsS0FBSyxDQUFDO3dDQUNWLEtBQUssS0FBSzs0Q0FDTixjQUFjLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsYUFBYSxDQUFDLENBQUM7NENBQ2xELEtBQUssQ0FBQzt3Q0FDVixLQUFLLE9BQU87NENBQ1IsY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQyxDQUFDOzRDQUNwRCxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQztnREFDWixJQUFJLEVBQUUscUJBQXFCOzZDQUM5QixDQUFDLENBQUM7NENBQ0gsS0FBSyxDQUFDO29DQUNkLENBQUM7Z0NBQ0wsQ0FBQyxDQUFDLENBQUM7Z0NBRUgsMkhBQTJIO2dDQUMzSCxNQUFNLENBQUMsVUFBVSxDQUFDO29DQUNkLE1BQU0sQ0FBQyxNQUFNLENBQUM7d0NBQ1YsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDOzRDQUNoQyxNQUFNLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxZQUFZLEVBQUUsQ0FBQztvQ0FDckQsQ0FBQyxDQUFDLENBQUM7Z0NBQ1AsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO2dDQUVSLENBQUMsQ0FBQyxjQUFjLEVBQUUsQ0FBQzs0QkFDdkIsQ0FBQzt3QkFDTCxDQUFDO3dCQUVELHlGQUF5Rjt3QkFDekYsU0FBUyxDQUFDLE9BQU8sRUFBRSxDQUFDO29CQUN4QixDQUFDLENBQUMsQ0FBQztnQkFDUCxDQUFDO2FBQ0o7WUFDRCxXQUFXLEVBQUUsV0FBVyxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUM7WUFDOUMsT0FBTyxFQUFFLElBQUk7WUFDYixJQUFJLEVBQUUsVUFBVSxLQUFLLEVBQUUsT0FBTztnQkFDMUIsd0RBQXdEO2dCQUN4RCxPQUFPLENBQUMsSUFBSSxDQUFDLDJCQUEyQixDQUFDLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQztvQkFDdkQsQ0FBQyxDQUFDLGVBQWUsRUFBRSxDQUFDO2dCQUN4QixDQUFDLENBQUMsQ0FBQztnQkFDSCw4REFBOEQ7Z0JBQzlELENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDO29CQUN2QixLQUFLLENBQUMsTUFBTSxDQUFDO3dCQUNULEtBQUssQ0FBQyxPQUFPLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQzt3QkFDbkMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDO29CQUN4QyxDQUFDLENBQUMsQ0FBQztnQkFDUCxDQUFDLENBQUMsQ0FBQztZQUNQLENBQUM7U0FDSixDQUFDO0lBQ04sQ0FBQztDQUNKLENBQUMsQ0FBQztBQzVJUCxPQUFPO0tBQ0YsTUFBTSxDQUFDLGNBQWMsQ0FBQztLQUN0QixTQUFTLENBQUMsaUJBQWlCLEVBQUUsQ0FBQyxtQkFBbUIsRUFBRSxhQUFhO0lBQzdELFVBQVUsaUJBQWlCLEVBQUUsV0FBVztRQUNwQyxNQUFNLENBQUM7WUFDSCxRQUFRLEVBQUUsR0FBRztZQUNiLEtBQUssRUFBRSxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUU7WUFDdkIsVUFBVSxFQUFFLENBQUMsUUFBUSxFQUFFLFVBQVUsRUFBRSxRQUFRO2dCQUN2QyxVQUFVLE1BQU0sRUFBRSxRQUFRLEVBQUUsTUFBTTtvQkFDOUIsaUJBQWlCLENBQUMsbUJBQW1CLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDO29CQUN4RCxpQkFBaUIsQ0FBQyxxQkFBcUIsQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUM7b0JBQzFELE1BQU0sQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLEdBQUcsR0FBRyxDQUFDO2dCQUN6QyxDQUFDO2FBQ0o7WUFDRCxXQUFXLEVBQUUsV0FBVyxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUM7WUFDOUMsT0FBTyxFQUFFLElBQUk7U0FDaEIsQ0FBQztJQUNOLENBQUM7Q0FDSixDQUFDLENBQUM7QUNsQlAsT0FBTztLQUNGLE1BQU0sQ0FBQyxjQUFjLENBQUM7S0FDdEIsU0FBUyxDQUFDLGdCQUFnQixFQUFFLENBQUMsVUFBVTtJQUNwQyxVQUFVLFFBQVE7UUFDZCxNQUFNLENBQUM7WUFDSCxRQUFRLEVBQUUsR0FBRztZQUNiLEtBQUssRUFBRSxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUU7WUFDdkIsSUFBSSxFQUFFLFVBQVUsS0FBSyxFQUFFLE9BQU87Z0JBQzFCLElBQUksUUFBUSxHQUFHLGNBQWMsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsR0FBRyx1QkFBdUIsQ0FBQztnQkFDM0YsSUFBSSxJQUFJLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUNyQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ2pDLENBQUM7U0FDSixDQUFDO0lBQ04sQ0FBQztDQUNKLENBQUMsQ0FBQztBQ2RQLE9BQU87S0FDRixNQUFNLENBQUMsY0FBYyxDQUFDO0tBQ3RCLFNBQVMsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLFVBQVUsRUFBRSxtQkFBbUIsRUFBRSxhQUFhO0lBQ3pFLFVBQVUsUUFBUSxFQUFFLGlCQUFpQixFQUFFLFdBQVc7UUFDOUMsTUFBTSxDQUFDO1lBQ0gsUUFBUSxFQUFFLEdBQUc7WUFDYixLQUFLLEVBQUUsRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFO1lBQ3ZCLFVBQVUsRUFBRSxDQUFDLFFBQVEsRUFBRSxVQUFVO2dCQUM3QixVQUFVLE1BQU0sRUFBRSxRQUFRO29CQUN0QixpQkFBaUIsQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUM7b0JBQ3hELGlCQUFpQixDQUFDLHFCQUFxQixDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsQ0FBQztvQkFDMUQsTUFBTSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsR0FBRyxHQUFHLENBQUM7Z0JBQ3pDLENBQUM7YUFDSjtZQUNELFdBQVcsRUFBRSxXQUFXLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQztZQUM5QyxPQUFPLEVBQUUsSUFBSTtZQUNiLElBQUksRUFBRSxVQUFVLEtBQUssRUFBRSxPQUFPLEVBQUUsS0FBSztnQkFDakMsT0FBTyxDQUFDLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxDQUFDLFNBQVMsQ0FBQztvQkFDaEQsSUFBSSxFQUFFLEdBQUc7b0JBQ1QsTUFBTSxFQUFFLE9BQU87b0JBQ2YsTUFBTSxFQUFFLElBQUk7b0JBQ1osS0FBSyxFQUFFLFVBQVUsQ0FBQyxFQUFFLEVBQUU7d0JBQ2xCLEtBQUssQ0FBQyxNQUFNLENBQUM7NEJBQ1QsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQzt3QkFDM0MsQ0FBQyxDQUFDLENBQUM7b0JBQ1AsQ0FBQztvQkFDRCxJQUFJLEVBQUUsVUFBVSxDQUFDLEVBQUUsRUFBRTt3QkFDakIsSUFBSSxhQUFhLEdBQUcsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDO3dCQUNyQyxJQUFJLFVBQVUsR0FBRyxhQUFhLENBQUMsS0FBSyxFQUFFLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7d0JBQzdELElBQUksZUFBZSxHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQzt3QkFDakMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxRQUFRLENBQUMsK0JBQStCLENBQUMsQ0FBQyxDQUFDLENBQUM7NEJBQ3hELElBQUksS0FBSyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxHQUFHLGFBQWEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUM7NEJBQ3pELEVBQUUsQ0FBQyxDQUFDLEtBQUssR0FBRyxDQUFDLFVBQVUsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0NBQ3RFLEtBQUssQ0FBQyxNQUFNLENBQUM7b0NBQ1QsS0FBSyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFDLENBQUM7Z0NBQzlDLENBQUMsQ0FBQyxDQUFDOzRCQUNQLENBQUM7NEJBQ0QsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssR0FBRyxVQUFVLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDO2dDQUM1RSxLQUFLLENBQUMsTUFBTSxDQUFDO29DQUNULEtBQUssQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLGVBQWUsQ0FBQyxDQUFDO2dDQUNoRCxDQUFDLENBQUMsQ0FBQzs0QkFDUCxDQUFDO3dCQUNMLENBQUM7d0JBQ0QsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsUUFBUSxDQUFDLGdDQUFnQyxDQUFDLENBQUMsQ0FBQyxDQUFDOzRCQUM5RCxJQUFJLEtBQUssR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksR0FBRyxhQUFhLENBQUMsS0FBSyxFQUFFLEdBQUcsYUFBYSxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQzs0QkFDakYsRUFBRSxDQUFDLENBQUMsS0FBSyxHQUFHLFVBQVUsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0NBQ3RFLEtBQUssQ0FBQyxNQUFNLENBQUM7b0NBQ1QsS0FBSyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsZUFBZSxDQUFDLENBQUM7Z0NBQy9DLENBQUMsQ0FBQyxDQUFDOzRCQUNQLENBQUM7NEJBQ0QsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssR0FBRyxDQUFDLFVBQVUsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQ0FDOUUsS0FBSyxDQUFDLE1BQU0sQ0FBQztvQ0FDVCxLQUFLLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxlQUFlLENBQUMsQ0FBQztnQ0FDakQsQ0FBQyxDQUFDLENBQUM7NEJBQ1AsQ0FBQzt3QkFDTCxDQUFDO29CQUVMLENBQUM7b0JBQ0QsSUFBSSxFQUFFLFVBQVUsQ0FBQyxFQUFFLEVBQUU7d0JBQ2pCLEtBQUssQ0FBQyxNQUFNLENBQUM7NEJBQ1gsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQzt3QkFDMUMsQ0FBQyxDQUFDLENBQUM7b0JBQ1AsQ0FBQztpQkFDSixDQUFDLENBQUM7WUFDUCxDQUFDO1NBQ0osQ0FBQztJQUNOLENBQUM7Q0FDSixDQUFDLENBQUM7QUNuRVAsT0FBTztLQUNGLE1BQU0sQ0FBQyxjQUFjLENBQUM7S0FDdEIsU0FBUyxDQUFDLGtCQUFrQixFQUFFLENBQUMsTUFBTSxFQUFFLG1CQUFtQixFQUFFLGFBQWE7SUFDdEUsVUFBVSxJQUFJLEVBQUUsaUJBQWlCLEVBQUUsV0FBVztRQUMxQyxNQUFNLENBQUM7WUFDSCxRQUFRLEVBQUUsR0FBRztZQUNiLEtBQUssRUFBRSxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUU7WUFDdkIsVUFBVSxFQUFFLENBQUMsUUFBUSxFQUFFLFVBQVU7Z0JBQzdCLFVBQVUsTUFBTSxFQUFFLFFBQVE7b0JBQ3RCLGlCQUFpQixDQUFDLG1CQUFtQixDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsQ0FBQztvQkFFeEQsMklBQTJJO29CQUMzSSxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sR0FBRyxVQUFVLElBQUk7d0JBQ25DLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQzt3QkFDM0IsTUFBTSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDdkQsQ0FBQyxDQUFDO29CQUVGLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ2hELENBQUM7YUFDSjtZQUNELFdBQVcsRUFBRSxXQUFXLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQztZQUMvQyxPQUFPLEVBQUUsSUFBSTtTQUNoQixDQUFDO0lBQ04sQ0FBQztDQUNKLENBQUMsQ0FBQztBQ3hCUCxPQUFPO0tBQ0YsTUFBTSxDQUFDLGNBQWMsQ0FBQztLQUN0QixTQUFTLENBQUMsZUFBZSxFQUFFLENBQUMsVUFBVSxFQUFFLG1CQUFtQixFQUFFLGFBQWE7SUFDdkUsVUFBVSxRQUFRLEVBQUUsaUJBQWlCLEVBQUUsV0FBVztRQUM5QyxNQUFNLENBQUM7WUFDSCxRQUFRLEVBQUUsR0FBRztZQUNiLEtBQUssRUFBRSxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUU7WUFDdkIsVUFBVSxFQUFFLENBQUMsUUFBUSxFQUFFLFVBQVU7Z0JBQzdCLFVBQVUsTUFBTSxFQUFFLFFBQVE7b0JBQ3RCLGlCQUFpQixDQUFDLG1CQUFtQixDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsQ0FBQztvQkFDeEQsaUJBQWlCLENBQUMscUJBQXFCLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDO29CQUMxRCxNQUFNLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxHQUFHLEdBQUcsQ0FBQztnQkFDekMsQ0FBQzthQUNKO1lBQ0QsV0FBVyxFQUFFLFdBQVcsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDO1lBQzVDLE9BQU8sRUFBRSxJQUFJO1NBQ2hCLENBQUM7SUFDTixDQUFDO0NBQ0osQ0FBQyxDQUFDO0FDbEJQLE9BQU87S0FDRixNQUFNLENBQUMsY0FBYyxDQUFDO0tBQ3RCLFNBQVMsQ0FBQyxjQUFjLEVBQUUsQ0FBQyxVQUFVLEVBQUUsbUJBQW1CLEVBQUUsYUFBYTtJQUN0RSxVQUFVLFFBQVEsRUFBRSxpQkFBaUIsRUFBRSxXQUFXO1FBQzlDLE1BQU0sQ0FBQztZQUNILFFBQVEsRUFBRSxHQUFHO1lBQ2IsS0FBSyxFQUFFLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRTtZQUN2QixVQUFVLEVBQUUsQ0FBQyxRQUFRLEVBQUUsVUFBVTtnQkFDN0IsVUFBVSxNQUFNLEVBQUUsUUFBUTtvQkFDdEIsaUJBQWlCLENBQUMsbUJBQW1CLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDO29CQUN4RCxpQkFBaUIsQ0FBQyxxQkFBcUIsQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUM7b0JBQzFELE1BQU0sQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLEdBQUcsR0FBRyxDQUFDO29CQUNyQyxNQUFNLENBQUMsZUFBZSxDQUFDLGFBQWEsQ0FBQyxHQUFHLElBQUksQ0FBQztnQkFDakQsQ0FBQzthQUNKO1lBQ0QsV0FBVyxFQUFFLFdBQVcsQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDO1lBQzNDLE9BQU8sRUFBRSxJQUFJO1NBQ2hCLENBQUM7SUFDTixDQUFDO0NBQ0osQ0FBQyxDQUFDO0FDbkJQLE9BQU87S0FDRixNQUFNLENBQUMsY0FBYyxDQUFDO0tBQ3RCLFNBQVMsQ0FBQyxnQkFBZ0IsRUFBRTtJQUN6QjtRQUNJLE1BQU0sQ0FBQztZQUNILFFBQVEsRUFBRSxHQUFHO1lBQ2IsSUFBSSxFQUFFLFVBQVUsS0FBSyxFQUFFLE9BQU8sRUFBRSxLQUFLO2dCQUNqQyxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ3ZCLElBQUksT0FBTyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsdUJBQXVCLENBQUMsQ0FBQztnQkFDckQsSUFBSSxhQUFhLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO2dCQUNyRCxPQUFPLENBQUMsS0FBSyxDQUFDO29CQUNWLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztvQkFDZixFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQzt3QkFDdkIsS0FBSyxDQUFDLFFBQVEsQ0FBQzs0QkFDWCxFQUFFLEVBQUUsS0FBSyxDQUFDLGdCQUFnQixJQUFJLFVBQVU7NEJBQ3hDLEVBQUUsRUFBRSxLQUFLLENBQUMsZ0JBQWdCLElBQUksaUJBQWlCOzRCQUMvQyxFQUFFLEVBQUUsT0FBTzt5QkFDZCxDQUFDLENBQUM7d0JBQ0gsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztvQkFDeEMsQ0FBQztnQkFDTCxDQUFDLENBQUMsQ0FBQztnQkFDSCxLQUFLLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQztvQkFDbkIsQ0FBQyxDQUFDLGVBQWUsRUFBRSxDQUFDO2dCQUN4QixDQUFDLENBQUMsQ0FBQztnQkFDSCxhQUFhLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQztvQkFDM0IsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDO2dCQUNqQixDQUFDLENBQUMsQ0FBQztnQkFDSCxLQUFLLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQztvQkFDckIsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUM7d0JBQ3hELEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztvQkFDakIsQ0FBQyxDQUFDLGVBQWUsRUFBRSxDQUFDO2dCQUN4QixDQUFDLENBQUMsQ0FBQztnQkFDSCxLQUFLLENBQUMsRUFBRSxDQUFDLGdCQUFnQixFQUFFLFVBQVUsQ0FBQztvQkFDbEMsbUdBQW1HO29CQUNuRyxDQUFDLENBQUMsZUFBZSxFQUFFLENBQUM7Z0JBQ3hCLENBQUMsQ0FBQyxDQUFDO1lBQ1AsQ0FBQztTQUNKLENBQUM7SUFDTixDQUFDO0NBQ0osQ0FBQyxDQUFDO0FDdkNQLE9BQU87S0FDRixNQUFNLENBQUMsY0FBYyxDQUFDO0tBQ3RCLFNBQVMsQ0FBQyxrQkFBa0IsRUFBRSxDQUFDLFVBQVUsRUFBRSxhQUFhO0lBQ3JELFVBQVUsUUFBUSxFQUFFLFdBQVc7UUFDM0IsTUFBTSxDQUFDO1lBQ0gsUUFBUSxFQUFFLEdBQUc7WUFDYixVQUFVLEVBQUUsQ0FBQyxRQUFRLEVBQUUsVUFBVTtnQkFDN0IsVUFBVSxNQUFNLEVBQUUsUUFBUTtvQkFFdEIsTUFBTSxDQUFDLGFBQWEsR0FBRzt3QkFFbkIsTUFBTSxDQUFDLFlBQVksR0FBRzs0QkFDbEIsWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7Z0NBQ25CLFdBQVcsRUFBRSxRQUFRO2dDQUNyQixZQUFZLEVBQUUsTUFBTTtnQ0FDcEIsa0JBQWtCLEVBQUUsYUFBYTtnQ0FDakMsUUFBUSxFQUFFLEVBQUU7NkJBQ2YsQ0FBQzt5QkFDTCxDQUFDO3dCQUVGLE1BQU0sQ0FBQyxXQUFXLEdBQUc7NEJBQ2pCLFlBQVksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDO2dDQUNsQixXQUFXLEVBQUUsUUFBUTtnQ0FDckIsWUFBWSxFQUFFLGdCQUFnQjtnQ0FDOUIsa0JBQWtCLEVBQUUsb0JBQW9CO2dDQUN4QyxRQUFRLEVBQUUsWUFBWSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDOzZCQUN6QyxDQUFDOzRCQUNGLFlBQVksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDO2dDQUNsQixXQUFXLEVBQUUsUUFBUTtnQ0FDckIsWUFBWSxFQUFFLGlCQUFpQjtnQ0FDL0Isa0JBQWtCLEVBQUUscUJBQXFCO2dDQUN6QyxRQUFRLEVBQUUsWUFBWSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDOzZCQUN6QyxDQUFDOzRCQUNGLFlBQVksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDO2dDQUNsQixXQUFXLEVBQUUsUUFBUTtnQ0FDckIsWUFBWSxFQUFFLGlCQUFpQjtnQ0FDL0Isa0JBQWtCLEVBQUUscUJBQXFCO2dDQUN6QyxRQUFRLEVBQUUsWUFBWSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDOzZCQUN6QyxDQUFDOzRCQUNGLFlBQVksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDO2dDQUNsQixXQUFXLEVBQUUsUUFBUTtnQ0FDckIsWUFBWSxFQUFFLGlCQUFpQjtnQ0FDL0Isa0JBQWtCLEVBQUUscUJBQXFCO2dDQUN6QyxRQUFRLEVBQUUsWUFBWSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDOzZCQUN6QyxDQUFDOzRCQUNGLFlBQVksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDO2dDQUNsQixXQUFXLEVBQUUsUUFBUTtnQ0FDckIsWUFBWSxFQUFFLGlCQUFpQjtnQ0FDL0Isa0JBQWtCLEVBQUUscUJBQXFCO2dDQUN6QyxRQUFRLEVBQUUsWUFBWSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDOzZCQUN6QyxDQUFDOzRCQUNGLFlBQVksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDO2dDQUNsQixXQUFXLEVBQUUsUUFBUTtnQ0FDckIsWUFBWSxFQUFFLGtCQUFrQjtnQ0FDaEMsa0JBQWtCLEVBQUUsc0JBQXNCO2dDQUMxQyxRQUFRLEVBQUUsWUFBWSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDOzZCQUMxQyxDQUFDLEVBQUUsWUFBWSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUM7Z0NBQ3RCLFdBQVcsRUFBRSxRQUFRO2dDQUNyQixZQUFZLEVBQUUsYUFBYTtnQ0FDM0Isa0JBQWtCLEVBQUUsWUFBWTtnQ0FDaEMsUUFBUSxFQUFFLEVBQUU7NkJBQ2YsQ0FBQzt5QkFDTCxDQUFDO3dCQUVGLE1BQU0sQ0FBQyxjQUFjLEdBQUc7NEJBQ3BCLFlBQVksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDO2dDQUNyQixXQUFXLEVBQUUsUUFBUTtnQ0FDckIsWUFBWSxFQUFFLFFBQVE7Z0NBQ3RCLGtCQUFrQixFQUFFLGVBQWU7Z0NBQ25DLEtBQUssRUFBRSxDQUFDO2dDQUNSLE1BQU0sRUFBRSxDQUFDO2dDQUNULFFBQVEsRUFBRSxFQUFFOzZCQUNmLENBQUM7eUJBQ0wsQ0FBQzt3QkFFRixNQUFNLENBQUMsY0FBYyxHQUFHOzRCQUNwQixZQUFZLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztnQ0FDckIsV0FBVyxFQUFFLFFBQVE7Z0NBQ3JCLFlBQVksRUFBRSxRQUFRO2dDQUN0QixrQkFBa0IsRUFBRSxlQUFlO2dDQUNuQyxRQUFRLEVBQUUsRUFBRTs2QkFDZixDQUFDO3lCQUNMLENBQUM7d0JBRUYsTUFBTSxDQUFDLHdCQUF3QixHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxHQUFHLENBQUMsVUFBVSxRQUFROzRCQUN4RixNQUFNLENBQUM7Z0NBQ0gsSUFBSSxFQUFFLFFBQVEsQ0FBQyxJQUFJO2dDQUNuQixRQUFRLEVBQUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQyxHQUFHLENBQUMsVUFBVSxXQUFXO29DQUN4RCxJQUFJLElBQUksR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFDO29DQUM1QixJQUFJLE9BQU8sR0FBRyxZQUFZLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLFlBQVksQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUM7b0NBQ2hGLElBQUksSUFBSSxHQUFHO3dDQUNQLFdBQVcsRUFBRSxLQUFLO3dDQUNsQixXQUFXLEVBQUUsV0FBVyxDQUFDLEVBQUU7d0NBQzNCLGdCQUFnQixFQUFFLFdBQVcsQ0FBQyxLQUFLO3dDQUNuQyxnQkFBZ0IsRUFBRSxXQUFXLENBQUMsU0FBUzt3Q0FDdkMsSUFBSSxFQUFFLElBQUk7d0NBQ1YsU0FBUyxFQUFFLFdBQVcsQ0FBQyxTQUFTO3dDQUNoQyxJQUFJLEVBQUUsV0FBVyxDQUFDLElBQUk7cUNBQ3pCLENBQUM7b0NBQ0YsSUFBSSxPQUFPLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO29DQUM1QixPQUFPLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQyxJQUFJLElBQUksUUFBUSxDQUFDO29DQUNuRCxPQUFPLENBQUMsWUFBWSxHQUFHLFdBQVcsQ0FBQyxLQUFLLENBQUM7b0NBQ3pDLE9BQU8sQ0FBQyxrQkFBa0IsR0FBRyxXQUFXLENBQUMsV0FBVyxDQUFDO29DQUNyRCxNQUFNLENBQUMsT0FBTyxDQUFDO2dDQUNuQixDQUFDLENBQUM7NkJBQ0wsQ0FBQzt3QkFDTixDQUFDLENBQUMsQ0FBQztvQkFFUCxDQUFDLENBQUM7b0JBRUYsTUFBTSxDQUFDLGFBQWEsRUFBRSxDQUFDO29CQUV2QixNQUFNLENBQUMsa0JBQWtCLEdBQUcsVUFBVSxJQUFJO3dCQUN0QyxJQUFJLFFBQVEsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO3dCQUM3RCxJQUFJLGFBQWEsQ0FBQzt3QkFDbEIsSUFBSSxrQkFBa0IsQ0FBQzt3QkFDdkIsSUFBSSxRQUFRLEdBQUcsS0FBSyxDQUFDO3dCQUVyQixNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDOzRCQUNYLEtBQUssTUFBTTtnQ0FDUCxhQUFhLEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxnQkFBZ0IsRUFBRSx1QkFBdUIsQ0FBQyxDQUFDO2dDQUM5RSxrQkFBa0IsR0FBRyxxRUFBcUUsQ0FBQztnQ0FDM0YsS0FBSyxDQUFDOzRCQUNWLEtBQUssS0FBSztnQ0FDTixhQUFhLEdBQUcsQ0FBQyxjQUFjLENBQUMsQ0FBQztnQ0FDakMsa0JBQWtCLEdBQUcsd0VBQXdFLENBQUM7Z0NBQzlGLEtBQUssQ0FBQzs0QkFDVixLQUFLLFFBQVE7Z0NBQ1QsYUFBYSxHQUFHLENBQUMsbUNBQW1DLENBQUMsQ0FBQztnQ0FDdEQsa0JBQWtCLEdBQUcsdUVBQXVFLENBQUM7Z0NBQzdGLFFBQVEsR0FBRyxJQUFJLENBQUMsQ0FBQyxvR0FBb0c7Z0NBQ3JILEtBQUssQ0FBQzs0QkFDVixLQUFLLFNBQVM7Z0NBQ1YsYUFBYSxHQUFHLENBQUMsZ0JBQWdCLEVBQUUsZ0JBQWdCLEVBQUUsdUJBQXVCLENBQUMsQ0FBQztnQ0FDOUUsa0JBQWtCLEdBQUcsdURBQXVELENBQUM7Z0NBQzdFLEtBQUssQ0FBQzs0QkFDVixLQUFLLFFBQVE7Z0NBQ1QsYUFBYSxHQUFHLENBQUMsZ0JBQWdCLEVBQUUsZ0JBQWdCLEVBQUUsdUJBQXVCLENBQUMsQ0FBQztnQ0FDOUUsa0JBQWtCLEdBQUcscUVBQXFFLENBQUM7Z0NBQzNGLEtBQUssQ0FBQzt3QkFDZCxDQUFDO3dCQUVELE1BQU0sQ0FBQzs0QkFDSCxNQUFNLEVBQUUsTUFBTTs0QkFDZCxXQUFXLEVBQUUsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsSUFBSSxNQUFNLENBQUMsR0FBRyxHQUFHLFFBQVEsR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLDZFQUE2RSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQzs0QkFDL0ssV0FBVyxFQUFFLGtCQUFrQjs0QkFDL0IsYUFBYSxFQUFFLFFBQVE7NEJBQ3ZCLE1BQU0sRUFBRSxPQUFPOzRCQUNmLFFBQVEsRUFBRSxNQUFNOzRCQUNoQixNQUFNLEVBQUUsVUFBVSxDQUFDLEVBQUUsRUFBRTtnQ0FDbkIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLENBQUMsa0ZBQWtGOzRCQUNqSCxDQUFDOzRCQUNELEtBQUssRUFBRSxVQUFVLENBQUMsRUFBRSxFQUFFO2dDQUNsQixNQUFNLENBQUMsTUFBTSxDQUFDO29DQUNWLE1BQU0sQ0FBQyxPQUFPLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztnQ0FDckMsQ0FBQyxDQUFDLENBQUM7NEJBQ1AsQ0FBQzs0QkFDRCxJQUFJLEVBQUUsVUFBVSxDQUFDLEVBQUUsRUFBRTtnQ0FDakIsTUFBTSxDQUFDLE1BQU0sQ0FBQztvQ0FDVixNQUFNLENBQUMsT0FBTyxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUM7b0NBQ2xDLE1BQU0sQ0FBQyxhQUFhLEVBQUUsQ0FBQztnQ0FDM0IsQ0FBQyxDQUFDLENBQUM7NEJBQ1AsQ0FBQzs0QkFDRCxJQUFJLEVBQUUsVUFBVSxDQUFDLEVBQUUsRUFBRTtnQ0FDakIsTUFBTSxDQUFDLE1BQU0sQ0FBQztvQ0FDVixNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUM7Z0NBQ2pELENBQUMsQ0FBQyxDQUFDOzRCQUNQLENBQUM7eUJBQ0osQ0FBQTtvQkFDTCxDQUFDLENBQUM7b0JBRUYsSUFBSSwyQkFBMkIsR0FBRywwQ0FBMEMsQ0FBQztvQkFDN0UsTUFBTSxDQUFDLGlCQUFpQixHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsMkJBQTJCLENBQUMsS0FBSyxNQUFNLENBQUM7b0JBRTVFLE1BQU0sQ0FBQyx1QkFBdUIsR0FBRyxVQUFVLENBQUM7d0JBQ3hDLE1BQU0sQ0FBQyxpQkFBaUIsR0FBRyxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQzt3QkFDckQsQ0FBQyxDQUFDLE1BQU0sQ0FBQywyQkFBMkIsRUFBRSxNQUFNLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLHVDQUF1Qzt3QkFDMUgsQ0FBQyxDQUFDLGNBQWMsRUFBRSxDQUFDO3dCQUNuQixDQUFDLENBQUMsZUFBZSxFQUFFLENBQUM7b0JBQ3hCLENBQUMsQ0FBQztnQkFDTixDQUFDO2FBQ0o7WUFDRCxXQUFXLEVBQUUsV0FBVyxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUM7WUFDL0MsT0FBTyxFQUFFLElBQUk7U0FDaEIsQ0FBQztJQUNOLENBQUM7Q0FDSixDQUFDLENBQUM7QUMxTFAsT0FBTztLQUNGLE1BQU0sQ0FBQyxjQUFjLENBQUM7S0FDdEIsU0FBUyxDQUFDLHVCQUF1QixFQUFFLENBQUMsVUFBVSxFQUFFLGFBQWE7SUFDMUQsVUFBVSxRQUFRLEVBQUUsV0FBVztRQUMzQixNQUFNLENBQUM7WUFDSCxRQUFRLEVBQUUsR0FBRztZQUNiLEtBQUssRUFBRSxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUU7WUFDeEIsVUFBVSxFQUFFLENBQUMsUUFBUSxFQUFFLFVBQVU7Z0JBQzdCLFVBQVUsTUFBTSxFQUFFLFFBQVE7b0JBQ3RCLElBQUkscUJBQXFCLEdBQUcsd0JBQXdCLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEdBQUcsY0FBYyxDQUFDO29CQUM3RixNQUFNLENBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMscUJBQXFCLENBQUMsS0FBSyxNQUFNLENBQUM7b0JBQ2hFLE1BQU0sQ0FBQyxpQkFBaUIsR0FBRyxVQUFVLENBQUM7d0JBQ2xDLE1BQU0sQ0FBQyxXQUFXLEdBQUcsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDO3dCQUN6QyxDQUFDLENBQUMsTUFBTSxDQUFDLHFCQUFxQixFQUFFLE1BQU0sQ0FBQyxXQUFXLEVBQUUsRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLHVDQUF1Qzt3QkFDOUcsQ0FBQyxDQUFDLGNBQWMsRUFBRSxDQUFDO3dCQUNuQixDQUFDLENBQUMsZUFBZSxFQUFFLENBQUM7b0JBQ3hCLENBQUMsQ0FBQztnQkFDTixDQUFDO2FBQ0o7WUFDRCxXQUFXLEVBQUUsV0FBVyxDQUFDLFdBQVcsQ0FBQyxjQUFjLENBQUM7WUFDcEQsT0FBTyxFQUFFLElBQUk7U0FDaEIsQ0FBQztJQUNOLENBQUM7Q0FDSixDQUFDLENBQUMiLCJmaWxlIjoiTGF5b3V0RWRpdG9yLmpzIiwic291cmNlc0NvbnRlbnQiOlsiYW5ndWxhci5tb2R1bGUoXCJMYXlvdXRFZGl0b3JcIiwgW1wibmdTYW5pdGl6ZVwiLCBcIm5nUmVzb3VyY2VcIiwgXCJ1aS5zb3J0YWJsZVwiXSk7IiwidmFyIExheW91dEVkaXRvcjtcclxuKGZ1bmN0aW9uKExheW91dEVkaXRvcikge1xyXG5cclxuICAgIHZhciBDbGlwYm9hcmQgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xyXG4gICAgICAgIHRoaXMuX2NsaXBib2FyZERhdGEgPSB7fTtcclxuICAgICAgICB0aGlzLl9pc0Rpc2FibGVkID0gZmFsc2U7XHJcbiAgICAgICAgdGhpcy5fd2FzSW52b2tlZCA9IGZhbHNlO1xyXG5cclxuICAgICAgICB0aGlzLnNldERhdGEgPSBmdW5jdGlvbihjb250ZW50VHlwZSwgZGF0YSkge1xyXG4gICAgICAgICAgICBzZWxmLl9jbGlwYm9hcmREYXRhW2NvbnRlbnRUeXBlXSA9IGRhdGE7XHJcbiAgICAgICAgICAgIHNlbGYuX3dhc0ludm9rZWQgPSB0cnVlO1xyXG4gICAgICAgIH07XHJcbiAgICAgICAgdGhpcy5nZXREYXRhID0gZnVuY3Rpb24gKGNvbnRlbnRUeXBlKSB7XHJcbiAgICAgICAgICAgIHNlbGYuX3dhc0ludm9rZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICByZXR1cm4gc2VsZi5fY2xpcGJvYXJkRGF0YVtjb250ZW50VHlwZV07XHJcbiAgICAgICAgfTtcclxuICAgICAgICB0aGlzLmRpc2FibGUgPSBmdW5jdGlvbigpIHtcclxuICAgICAgICAgICAgc2VsZi5faXNEaXNhYmxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgIHNlbGYuX3dhc0ludm9rZWQgPSBmYWxzZTtcclxuICAgICAgICAgICAgc2VsZi5fY2xpcGJvYXJkRGF0YSA9IHt9O1xyXG4gICAgICAgIH07XHJcbiAgICAgICAgdGhpcy5pc0Rpc2FibGVkID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICByZXR1cm4gc2VsZi5faXNEaXNhYmxlZDtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy53YXNJbnZva2VkID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICByZXR1cm4gc2VsZi5fd2FzSW52b2tlZDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLkNsaXBib2FyZCA9IG5ldyBDbGlwYm9hcmQoKTtcclxuXHJcbiAgICBhbmd1bGFyXHJcbiAgICAgICAgLm1vZHVsZShcIkxheW91dEVkaXRvclwiKVxyXG4gICAgICAgIC5mYWN0b3J5KFwiY2xpcGJvYXJkXCIsIFtcclxuICAgICAgICAgICAgZnVuY3Rpb24oKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHNldERhdGE6IExheW91dEVkaXRvci5DbGlwYm9hcmQuc2V0RGF0YSxcclxuICAgICAgICAgICAgICAgICAgICBnZXREYXRhOiBMYXlvdXRFZGl0b3IuQ2xpcGJvYXJkLmdldERhdGEsXHJcbiAgICAgICAgICAgICAgICAgICAgZGlzYWJsZTogTGF5b3V0RWRpdG9yLkNsaXBib2FyZC5kaXNhYmxlLFxyXG4gICAgICAgICAgICAgICAgICAgIGlzRGlzYWJsZWQ6IExheW91dEVkaXRvci5DbGlwYm9hcmQuaXNEaXNhYmxlZCxcclxuICAgICAgICAgICAgICAgICAgICB3YXNJbnZva2VkOiBMYXlvdXRFZGl0b3IuQ2xpcGJvYXJkLndhc0ludm9rZWRcclxuICAgICAgICAgICAgICAgIH07XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICBdKTtcclxufSkoTGF5b3V0RWRpdG9yIHx8IChMYXlvdXRFZGl0b3IgPSB7fSkpOyIsImFuZ3VsYXJcclxuICAgIC5tb2R1bGUoXCJMYXlvdXRFZGl0b3JcIilcclxuICAgIC5mYWN0b3J5KFwic2NvcGVDb25maWd1cmF0b3JcIiwgW1wiJHRpbWVvdXRcIiwgXCJjbGlwYm9hcmRcIixcclxuICAgICAgICBmdW5jdGlvbiAoJHRpbWVvdXQsIGNsaXBib2FyZCkge1xyXG4gICAgICAgICAgICByZXR1cm4ge1xyXG5cclxuICAgICAgICAgICAgICAgIGNvbmZpZ3VyZUZvckVsZW1lbnQ6IGZ1bmN0aW9uICgkc2NvcGUsICRlbGVtZW50KSB7XHJcbiAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAkZWxlbWVudC5maW5kKFwiLmxheW91dC1wYW5lbFwiKS5jbGljayhmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAkZWxlbWVudC5wYXJlbnQoKS5rZXlkb3duKGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBoYW5kbGVkID0gZmFsc2U7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZXNldEZvY3VzID0gZmFsc2U7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBlbGVtZW50ID0gJHNjb3BlLmVsZW1lbnQ7XHJcbiAgICAgICAgICAgICAgICAgICAgXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50LmVkaXRvci5pc0RyYWdnaW5nKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSWYgbmF0aXZlIGNsaXBib2FyZCBzdXBwb3J0IGV4aXN0cywgdGhlIHBzZXVkby1jbGlwYm9hcmQgd2lsbCBoYXZlIGJlZW4gZGlzYWJsZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghY2xpcGJvYXJkLmlzRGlzYWJsZWQoKSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZvY3VzZWRFbGVtZW50ID0gZWxlbWVudC5lZGl0b3IuZm9jdXNlZEVsZW1lbnQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISFmb2N1c2VkRWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFBzZXVkbyBjbGlwYm9hcmQgaGFuZGxpbmcgZm9yIGJyb3dzZXJzIG5vdCBhbGxvd2luZyByZWFsIGNsaXBib2FyZCBvcGVyYXRpb25zLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlLmN0cmxLZXkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3dpdGNoIChlLndoaWNoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgNjc6IC8vIENcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvY3VzZWRFbGVtZW50LmNvcHkoY2xpcGJvYXJkKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIDg4OiAvLyBYXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb2N1c2VkRWxlbWVudC5jdXQoY2xpcGJvYXJkKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIDg2OiAvLyBWXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb2N1c2VkRWxlbWVudC5wYXN0ZShjbGlwYm9hcmQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghZS5jdHJsS2V5ICYmICFlLnNoaWZ0S2V5ICYmICFlLmFsdEtleSAmJiBlLndoaWNoID09IDQ2KSB7IC8vIERlbFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmRlbGV0ZShlbGVtZW50KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCFlLmN0cmxLZXkgJiYgIWUuc2hpZnRLZXkgJiYgIWUuYWx0S2V5ICYmIChlLndoaWNoID09IDMyIHx8IGUud2hpY2ggPT0gMjcpKSB7IC8vIFNwYWNlIG9yIEVzY1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJGVsZW1lbnQuZmluZChcIi5sYXlvdXQtcGFuZWwtYWN0aW9uLXByb3BlcnRpZXNcIikuZmlyc3QoKS5jbGljaygpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghIWVsZW1lbnQuaGFzRWRpdG9yKSB7IC8vIFRoaXMgZWxlbWVudCBoYXMgYW4gZWRpdG9yIGRpYWxvZy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghZS5jdHJsS2V5ICYmICFlLnNoaWZ0S2V5ICYmICFlLmFsdEtleSAmJiBlLndoaWNoID09IDEzKSB7IC8vIEVudGVyXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJGVsZW1lbnQuZmluZChcIi5sYXlvdXQtcGFuZWwtYWN0aW9uLWVkaXRcIikuZmlyc3QoKS5jbGljaygpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoISFlbGVtZW50LmNoaWxkcmVuKSB7IC8vIFRoaXMgaXMgYSBjb250YWluZXIuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWUuY3RybEtleSAmJiAhZS5zaGlmdEtleSAmJiBlLmFsdEtleSAmJiBlLndoaWNoID09IDQwKSB7IC8vIEFsdCtEb3duXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVsZW1lbnQuY2hpbGRyZW4ubGVuZ3RoID4gMClcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5jaGlsZHJlblswXS5zZXRJc0ZvY3VzZWQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYW5kbGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZWxlbWVudC50eXBlID09IFwiQ29sdW1uXCIpIHsgLy8gVGhpcyBpcyBhIGNvbHVtbi5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgY29ubmVjdEFkamFjZW50ID0gIWUuY3RybEtleTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZS53aGljaCA9PSAzNykgeyAvLyBMZWZ0XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlLmFsdEtleSlcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuZXhwYW5kTGVmdChjb25uZWN0QWRqYWNlbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZS5zaGlmdEtleSlcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuY29udHJhY3RSaWdodChjb25uZWN0QWRqYWNlbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYW5kbGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGUud2hpY2ggPT0gMzkpIHsgLy8gUmlnaHRcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGUuYWx0S2V5KVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5jb250cmFjdExlZnQoY29ubmVjdEFkamFjZW50KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGUuc2hpZnRLZXkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LmV4cGFuZFJpZ2h0KGNvbm5lY3RBZGphY2VudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEhZWxlbWVudC5wYXJlbnQpIHsgLy8gVGhpcyBpcyBhIGNoaWxkLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGUuYWx0S2V5ICYmIGUud2hpY2ggPT0gMzgpIHsgLy8gQWx0K1VwXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5wYXJlbnQuc2V0SXNGb2N1c2VkKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVsZW1lbnQucGFyZW50LnR5cGUgPT0gXCJSb3dcIikgeyAvLyBQYXJlbnQgaXMgYSBob3Jpem9udGFsIGNvbnRhaW5lci5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWUuY3RybEtleSAmJiAhZS5zaGlmdEtleSAmJiAhZS5hbHRLZXkgJiYgZS53aGljaCA9PSAzNykgeyAvLyBMZWZ0XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQucGFyZW50Lm1vdmVGb2N1c1ByZXZDaGlsZChlbGVtZW50KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKCFlLmN0cmxLZXkgJiYgIWUuc2hpZnRLZXkgJiYgIWUuYWx0S2V5ICYmIGUud2hpY2ggPT0gMzkpIHsgLy8gUmlnaHRcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5wYXJlbnQubW92ZUZvY3VzTmV4dENoaWxkKGVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYW5kbGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoZS5jdHJsS2V5ICYmICFlLnNoaWZ0S2V5ICYmICFlLmFsdEtleSAmJiBlLndoaWNoID09IDM3KSB7IC8vIEN0cmwrTGVmdFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50Lm1vdmVVcCgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNldEZvY3VzID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKGUuY3RybEtleSAmJiAhZS5zaGlmdEtleSAmJiAhZS5hbHRLZXkgJiYgZS53aGljaCA9PSAzOSkgeyAvLyBDdHJsK1JpZ2h0XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQubW92ZURvd24oKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7IC8vIFBhcmVudCBpcyBhIHZlcnRpY2FsIGNvbnRhaW5lci5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWUuY3RybEtleSAmJiAhZS5zaGlmdEtleSAmJiAhZS5hbHRLZXkgJiYgZS53aGljaCA9PSAzOCkgeyAvLyBVcFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LnBhcmVudC5tb3ZlRm9jdXNQcmV2Q2hpbGQoZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmICghZS5jdHJsS2V5ICYmICFlLnNoaWZ0S2V5ICYmICFlLmFsdEtleSAmJiBlLndoaWNoID09IDQwKSB7IC8vIERvd25cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5wYXJlbnQubW92ZUZvY3VzTmV4dENoaWxkKGVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYW5kbGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoZS5jdHJsS2V5ICYmICFlLnNoaWZ0S2V5ICYmICFlLmFsdEtleSAmJiBlLndoaWNoID09IDM4KSB7IC8vIEN0cmwrVXBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5tb3ZlVXAoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzZXRGb2N1cyA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChlLmN0cmxLZXkgJiYgIWUuc2hpZnRLZXkgJiYgIWUuYWx0S2V5ICYmIGUud2hpY2ggPT0gNDApIHsgLy8gQ3RybCtEb3duXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQubW92ZURvd24oKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFuZGxlZCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLiRhcHBseSgpOyAvLyBFdmVudCBpcyBub3QgdHJpZ2dlcmVkIGJ5IEFuZ3VsYXIgZGlyZWN0aXZlIGJ1dCByYXcgZXZlbnQgaGFuZGxlciBvbiBlbGVtZW50LlxyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSEFDSzogV29ya2Fyb3VuZCBiZWNhdXNlIG9mIGhvdyBBbmd1bGFyIHRyZWF0cyB0aGUgRE9NIHdoZW4gZWxlbWVudHMgYXJlIHNoaWZ0ZWQgYXJvdW5kIC0gaW5wdXQgZm9jdXMgaXMgc29tZXRpbWVzIGxvc3QuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXNldEZvY3VzKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aW5kb3cuc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLiRhcHBseShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuZWRpdG9yLmZvY3VzZWRFbGVtZW50LnNldElzRm9jdXNlZCgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSwgMTAwKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZWxlbWVudC5zZXRJc0ZvY3VzZWRFdmVudEhhbmRsZXJzLnB1c2goZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAkZWxlbWVudC5wYXJlbnQoKS5mb2N1cygpO1xyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZGVsZXRlID0gZnVuY3Rpb24gKGVsZW1lbnQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5kZWxldGUoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgJC5ldmVudC50cmlnZ2VyKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6IFwibGF5b3V0ZWRpdG9yOmVkaXRlZFwiXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCRzY29wZS5lbGVtZW50Lmhhc0VkaXRvcikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZWRpdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kcm9vdC5lZGl0RWxlbWVudCgkc2NvcGUuZWxlbWVudCkuZG9uZShmdW5jdGlvbiAoYXJncykge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kYXBwbHkoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoYXJncy5jYW5jZWwpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZWxlbWVudC5kYXRhID0gYXJncy5lbGVtZW50LmRhdGE7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5lbGVtZW50LmFwcGx5RWxlbWVudEVkaXRvck1vZGVsKGFyZ3MuZWxlbWVudEVkaXRvck1vZGVsKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghISRzY29wZS5lbGVtZW50LnNldEh0bWwpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZWxlbWVudC5zZXRIdG1sKGFyZ3MuZWxlbWVudC5odG1sKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0sXHJcblxyXG4gICAgICAgICAgICAgICAgY29uZmlndXJlRm9yQ29udGFpbmVyOiBmdW5jdGlvbiAoJHNjb3BlLCAkZWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciBlbGVtZW50ID0gJHNjb3BlLmVsZW1lbnQ7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIC8vJHNjb3BlLmlzUmVjZWl2aW5nID0gZmFsc2U7IC8vIFRydWUgd2hlbiBjb250YWluZXIgaXMgcmVjZWl2aW5nIGFuIGV4dGVybmFsIGVsZW1lbnQgdmlhIGRyYWcvZHJvcC5cclxuICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZ2V0U2hvd0NoaWxkcmVuUGxhY2Vob2xkZXIgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAkc2NvcGUuZWxlbWVudC5jaGlsZHJlbi5sZW5ndGggPT09IDAgJiYgISRzY29wZS5lbGVtZW50LmdldElzRHJvcFRhcmdldCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICRzY29wZS5zb3J0YWJsZU9wdGlvbnMgPSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGN1cnNvcjogXCJtb3ZlXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGF5OiAxNTAsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc2FibGVkOiBlbGVtZW50LmdldElzU2VhbGVkKCksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc3RhbmNlOiA1LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvL2hhbmRsZTogZWxlbWVudC5jaGlsZHJlbi5sZW5ndGggPCAyID8gXCIuaW1hZ2luYXJ5LWNsYXNzXCIgOiBmYWxzZSwgLy8gRm9yIHNvbWUgcmVhc29uIGRvZXNuJ3QgZ2V0IHJlLWV2YWx1YXRlZCBhZnRlciBhZGRpbmcgbW9yZSBjaGlsZHJlbi5cclxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQ6IGZ1bmN0aW9uIChlLCB1aSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLiRhcHBseShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5zZXRJc0Ryb3BUYXJnZXQodHJ1ZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5lZGl0b3IuaXNEcmFnZ2luZyA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1ha2UgdGhlIGRyb3AgdGFyZ2V0IHBsYWNlaG9sZGVyIGFzIGhpZ2ggYXMgdGhlIGl0ZW0gYmVpbmcgZHJhZ2dlZC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpLnBsYWNlaG9sZGVyLmhlaWdodCh1aS5pdGVtLmhlaWdodCgpIC0gNCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aS5wbGFjZWhvbGRlci5jc3MoXCJtaW4taGVpZ2h0XCIsIDApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBzdG9wOiBmdW5jdGlvbiAoZSwgdWkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kYXBwbHkoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuZWRpdG9yLmlzRHJhZ2dpbmcgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LnNldElzRHJvcFRhcmdldChmYWxzZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgb3ZlcjogZnVuY3Rpb24gKGUsIHVpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISF1aS5zZW5kZXIgJiYgISF1aS5zZW5kZXJbMF0uaXNUb29sYm94KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEhdWkuc2VuZGVyWzBdLmRyb3BUYXJnZXRUaW1lb3V0KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICR0aW1lb3V0LmNhbmNlbCh1aS5zZW5kZXJbMF0uZHJvcFRhcmdldFRpbWVvdXQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aS5zZW5kZXJbMF0uZHJvcFRhcmdldFRpbWVvdXQgPSBudWxsO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkdGltZW91dChmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50LnR5cGUgPT0gXCJSb3dcIikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhlcmUgd2FzIGEgcHJldmlvdXMgZHJvcCB0YXJnZXQgYW5kIGl0IHdhcyBhIHJvdywgcm9sbCBiYWNrIGFueSBwZW5kaW5nIGNvbHVtbiBhZGRzIHRvIGl0LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHByZXZpb3VzRHJvcFRhcmdldCA9IGVsZW1lbnQuZWRpdG9yLmRyb3BUYXJnZXRFbGVtZW50O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEhcHJldmlvdXNEcm9wVGFyZ2V0ICYmIHByZXZpb3VzRHJvcFRhcmdldC50eXBlID09IFwiUm93XCIpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJldmlvdXNEcm9wVGFyZ2V0LnJvbGxiYWNrQWRkQ29sdW1uKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5zZXRJc0Ryb3BUYXJnZXQoZmFsc2UpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpLnNlbmRlclswXS5kcm9wVGFyZ2V0VGltZW91dCA9ICR0aW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVsZW1lbnQudHlwZSA9PSBcIlJvd1wiKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVjZWl2ZWRDb2x1bW4gPSB1aS5pdGVtLnNvcnRhYmxlLm1vZGVsO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlY2VpdmVkQ29sdW1uV2lkdGggPSBNYXRoLmZsb29yKDEyIC8gKGVsZW1lbnQuY2hpbGRyZW4ubGVuZ3RoICsgMSkpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZWRDb2x1bW4ud2lkdGggPSByZWNlaXZlZENvbHVtbldpZHRoO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZWRDb2x1bW4ub2Zmc2V0ID0gMDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuYmVnaW5BZGRDb2x1bW4ocmVjZWl2ZWRDb2x1bW5XaWR0aCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNYWtlIHRoZSBkcm9wIHRhcmdldCBwbGFjZWhvbGRlciB0aGUgY29ycmVjdCB3aWR0aCBhbmQgYXMgaGlnaCBhcyB0aGUgaGlnaGVzdCBleGlzdGluZyBjb2x1bW4gaW4gdGhlIHJvdy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBtYXhIZWlnaHQgPSBfLm1heChfKCRlbGVtZW50LmZpbmQoXCI+IC5sYXlvdXQtY2hpbGRyZW4gPiAubGF5b3V0LWNvbHVtbjpub3QoLnVpLXNvcnRhYmxlLXBsYWNlaG9sZGVyKVwiKSkubWFwKGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICQoZSkuaGVpZ2h0KCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGkgPSAxOyBpIDw9IDEyOyBpKyspXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdWkucGxhY2Vob2xkZXIucmVtb3ZlQ2xhc3MoXCJjb2wteHMtXCIgKyBpKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpLnBsYWNlaG9sZGVyLmFkZENsYXNzKFwiY29sLXhzLVwiICsgcmVjZWl2ZWRDb2x1bW4ud2lkdGgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1heEhlaWdodCA+IDApIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aS5wbGFjZWhvbGRlci5oZWlnaHQobWF4SGVpZ2h0KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aS5wbGFjZWhvbGRlci5jc3MoXCJtaW4taGVpZ2h0XCIsIDApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdWkucGxhY2Vob2xkZXIuaGVpZ2h0KDApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpLnBsYWNlaG9sZGVyLmNzcyhcIm1pbi1oZWlnaHRcIiwgXCJcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5zZXRJc0Ryb3BUYXJnZXQodHJ1ZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSwgMTUwKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZTogZnVuY3Rpb24gKGUsIHVpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISF1aS5zZW5kZXIgJiYgISF1aS5zZW5kZXJbMF0uaXNUb29sYm94KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLiRhcHBseShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZWNlaXZlZEVsZW1lbnQgPSB1aS5pdGVtLnNvcnRhYmxlLm1vZGVsO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISFyZWNlaXZlZEVsZW1lbnQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50LnR5cGUgPT0gXCJSb3dcIilcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LmNvbW1pdEFkZENvbHVtbigpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2hvdWxkIGlkZWFsbHkgY2FsbCBMYXlvdXRFZGl0b3IuQ29udGFpbmVyLmFkZENoaWxkKCkgaW5zdGVhZCwgYnV0IHNpbmNlIHRoaXMgaGFuZGxlclxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXMgcnVuICpiZWZvcmUqIHRoZSB1aS1zb3J0YWJsZSBkaXJlY3RpdmUncyBoYW5kbGVyLCBpZiB3ZSB0cnkgdG8gYWRkIHRoZSBjaGlsZCB0byB0aGVcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFycmF5IHRoYXQgaGFuZGxlciB3aWxsIGdldCBhbiBleGNlcHRpb24gd2hlbiB0cnlpbmcgdG8gZG8gdGhlIHNhbWUuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBCZWNhdXNlIG9mIHRoaXMsIHdlIG5lZWQgdG8gaW52b2tlIFwic2V0UGFyZW50XCIgc28gdGhhdCBzcGVjaWZpYyBjb250YWluZXIgdHlwZXMgY2FuIHBlcmZvcm0gZWxlbWVudCBzcGVmaWNpYyBpbml0aWFsaXphdGlvbi5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmVkRWxlbWVudC5zZXRFZGl0b3IoZWxlbWVudC5lZGl0b3IpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZWRFbGVtZW50LnNldFBhcmVudChlbGVtZW50KTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISFyZWNlaXZlZEVsZW1lbnQuaGFzRWRpdG9yKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLiRyb290LmVkaXRFbGVtZW50KHJlY2VpdmVkRWxlbWVudCkuZG9uZShmdW5jdGlvbiAoYXJncykge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWFyZ3MuY2FuY2VsKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNlaXZlZEVsZW1lbnQuZGF0YSA9IGFyZ3MuZWxlbWVudC5kYXRhO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZWRFbGVtZW50LmFwcGx5RWxlbWVudEVkaXRvck1vZGVsKGFyZ3MuZWxlbWVudEVkaXRvck1vZGVsKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISFyZWNlaXZlZEVsZW1lbnQuc2V0SHRtbClcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNlaXZlZEVsZW1lbnQuc2V0SHRtbChhcmdzLmVsZW1lbnQuaHRtbCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHRpbWVvdXQoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEhYXJncy5jYW5jZWwpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZWRFbGVtZW50LmRlbGV0ZSgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlY2VpdmVkRWxlbWVudC5zZXRJc0ZvY3VzZWQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vJHNjb3BlLmlzUmVjZWl2aW5nID0gZmFsc2U7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LnNldElzRHJvcFRhcmdldChmYWxzZSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICR0aW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vJHNjb3BlLmlzUmVjZWl2aW5nID0gZmFsc2U7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50LnNldElzRHJvcFRhcmdldChmYWxzZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISFyZWNlaXZlZEVsZW1lbnQpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjZWl2ZWRFbGVtZW50LnNldElzRm9jdXNlZCgpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kcm9vdC5hZGRFbGVtZW50KHJlY2VpdmVkRWxlbWVudCkuZG9uZShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmNsaWNrID0gZnVuY3Rpb24gKGNoaWxkLCBlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghY2hpbGQuZWRpdG9yLmlzRHJhZ2dpbmcpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGlsZC5zZXRJc0ZvY3VzZWQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgICAgICAgICAgICAgICAgICB9O1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZ2V0Q2xhc3NlcyA9IGZ1bmN0aW9uIChjaGlsZCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVzdWx0ID0gW1wibGF5b3V0LWVsZW1lbnRcIl07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoISFjaGlsZC5jaGlsZHJlbikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goXCJsYXlvdXQtY29udGFpbmVyXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNoaWxkLmdldElzU2VhbGVkKCkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goXCJsYXlvdXQtY29udGFpbmVyLXNlYWxlZFwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goXCJsYXlvdXQtXCIgKyBjaGlsZC50eXBlLnRvTG93ZXJDYXNlKCkpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEhY2hpbGQuZHJvcFRhcmdldENsYXNzKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goY2hpbGQuZHJvcFRhcmdldENsYXNzKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRPRE86IE1vdmUgdGhlc2UgdG8gZWl0aGVyIHRoZSBDb2x1bW4gZGlyZWN0aXZlIG9yIHRoZSBDb2x1bW4gbW9kZWwgY2xhc3MuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjaGlsZC50eXBlID09IFwiUm93XCIpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKFwicm93XCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFjaGlsZC5jYW5BZGRDb2x1bW4oKSlcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChcImxheW91dC1yb3ctZnVsbFwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2hpbGQudHlwZSA9PSBcIkNvbHVtblwiKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChcImNvbC14cy1cIiArIGNoaWxkLndpZHRoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKFwiY29sLXhzLW9mZnNldC1cIiArIGNoaWxkLm9mZnNldCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNoaWxkLnR5cGUgPT0gXCJDb250ZW50XCIpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChcImxheW91dC1jb250ZW50LVwiICsgY2hpbGQuY29udGVudFR5cGVDbGFzcyk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2hpbGQuZ2V0SXNBY3RpdmUoKSlcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKFwibGF5b3V0LWVsZW1lbnQtYWN0aXZlXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2hpbGQuZ2V0SXNGb2N1c2VkKCkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChcImxheW91dC1lbGVtZW50LWZvY3VzZWRcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjaGlsZC5nZXRJc1NlbGVjdGVkKCkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChcImxheW91dC1lbGVtZW50LXNlbGVjdGVkXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2hpbGQuZ2V0SXNEcm9wVGFyZ2V0KCkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChcImxheW91dC1lbGVtZW50LWRyb3B0YXJnZXRcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjaGlsZC5pc1RlbXBsYXRlZClcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKFwibGF5b3V0LWVsZW1lbnQtdGVtcGxhdGVkXCIpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgICAgICAgICAgICAgICAgICB9O1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9O1xyXG4gICAgICAgIH1cclxuICAgIF0pOyIsImFuZ3VsYXJcclxuICAgIC5tb2R1bGUoXCJMYXlvdXRFZGl0b3JcIilcclxuICAgIC5kaXJlY3RpdmUoXCJvcmNMYXlvdXRFZGl0b3JcIiwgW1wiZW52aXJvbm1lbnRcIixcclxuICAgICAgICBmdW5jdGlvbiAoZW52aXJvbm1lbnQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICAgIHJlc3RyaWN0OiBcIkVcIixcclxuICAgICAgICAgICAgICAgIHNjb3BlOiB7fSxcclxuICAgICAgICAgICAgICAgIGNvbnRyb2xsZXI6IFtcIiRzY29wZVwiLCBcIiRlbGVtZW50XCIsIFwiJGF0dHJzXCIsIFwiJGNvbXBpbGVcIiwgXCJjbGlwYm9hcmRcIixcclxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoJHNjb3BlLCAkZWxlbWVudCwgJGF0dHJzLCAkY29tcGlsZSwgY2xpcGJvYXJkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghISRhdHRycy5tb2RlbClcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5lbGVtZW50ID0gZXZhbCgkYXR0cnMubW9kZWwpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUaGUgJ21vZGVsJyBhdHRyaWJ1dGUgbXVzdCBldmFsdWF0ZSB0byBhIExheW91dEVkaXRvci5FZGl0b3Igb2JqZWN0LlwiKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5jbGljayA9IGZ1bmN0aW9uIChjYW52YXMsIGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghY2FudmFzLmVkaXRvci5pc0RyYWdnaW5nKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhbnZhcy5zZXRJc0ZvY3VzZWQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZ2V0Q2xhc3NlcyA9IGZ1bmN0aW9uIChjYW52YXMpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZXN1bHQgPSBbXCJsYXlvdXQtZWxlbWVudFwiLCBcImxheW91dC1jb250YWluZXJcIiwgXCJsYXlvdXQtY2FudmFzXCJdO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjYW52YXMuZ2V0SXNBY3RpdmUoKSlcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChcImxheW91dC1lbGVtZW50LWFjdGl2ZVwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjYW52YXMuZ2V0SXNGb2N1c2VkKCkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goXCJsYXlvdXQtZWxlbWVudC1mb2N1c2VkXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNhbnZhcy5nZXRJc1NlbGVjdGVkKCkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goXCJsYXlvdXQtZWxlbWVudC1zZWxlY3RlZFwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjYW52YXMuZ2V0SXNEcm9wVGFyZ2V0KCkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2goXCJsYXlvdXQtZWxlbWVudC1kcm9wdGFyZ2V0XCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNhbnZhcy5pc1RlbXBsYXRlZClcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChcImxheW91dC1lbGVtZW50LXRlbXBsYXRlZFwiKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQW4gdW5mb3J0dW5hdGUgc2lkZS1lZmZlY3Qgb2YgdGhlIG5leHQgaGFjayBvbiBsaW5lIDU0IGlzIHRoYXQgdGhlIGNyZWF0ZWQgZWxlbWVudHMgYXJlbid0IGFkZGVkIHRvIHRoZSBET00geWV0LCBzbyB3ZSBjYW4ndCB1c2UgaXQgdG8gZ2V0IHRvIHRoZSBwYXJlbnQgXCIubGF5b3V0LWRlc2lnZXJcIiBlbGVtZW50LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBXb3JrIGFyb3VuZDogYWNjZXNzIHRoYXQgZWxlbWVudCBkaXJlY3RseSAod2hpY2ggZWZlY3RpdmVseSB0dXJucyBtdWx0aXBsZSBsYXlvdXQgZWRpdG9ycyBvbiBhIHNpbmdsZSBwYWdlIGltcG9zc2libGUpLiBcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gLy92YXIgbGF5b3V0RGVzaWduZXJIb3N0ID0gJGVsZW1lbnQuY2xvc2VzdChcIi5sYXlvdXQtZGVzaWduZXJcIikuZGF0YShcImxheW91dC1kZXNpZ25lci1ob3N0XCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgbGF5b3V0RGVzaWduZXJIb3N0ID0gJChcIi5sYXlvdXQtZGVzaWduZXJcIikuZGF0YShcImxheW91dC1kZXNpZ25lci1ob3N0XCIpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLiRyb290LmxheW91dERlc2lnbmVySG9zdCA9IGxheW91dERlc2lnbmVySG9zdDtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGxheW91dERlc2lnbmVySG9zdC5lbGVtZW50Lm9uKFwicmVwbGFjZWNhbnZhc1wiLCBmdW5jdGlvbiAoZSwgYXJncykge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGVkaXRvciA9ICRzY29wZS5lbGVtZW50O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGNhbnZhc0RhdGEgPSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YTogYXJncy5jYW52YXMuZGF0YSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBodG1sSWQ6IGFyZ3MuY2FudmFzLmh0bWxJZCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBodG1sQ2xhc3M6IGFyZ3MuY2FudmFzLmh0bWxDbGFzcyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBodG1sU3R5bGU6IGFyZ3MuY2FudmFzLmh0bWxTdHlsZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc1RlbXBsYXRlZDogYXJncy5jYW52YXMuaXNUZW1wbGF0ZWQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW46IGFyZ3MuY2FudmFzLmNoaWxkcmVuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9O1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEhBQ0s6IEluc3RlYWQgb2Ygc2ltcGx5IHVwZGF0aW5nIHRoZSAkc2NvcGUuZWxlbWVudCB3aXRoIGEgbmV3IGluc3RhbmNlLCB3ZSBuZWVkIHRvIHJlcGxhY2UgdGhlIGVudGlyZSBvcmMtbGF5b3V0LWVkaXRvciBtYXJrdXBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGluIG9yZGVyIGZvciBhbmd1bGFyIHRvIHJlYmluZCBzdGFydGluZyB3aXRoIHRoZSBDYW52YXMgZWxlbWVudC4gT3RoZXJ3aXNlLCBmb3Igc29tZSByZWFzb24sIGl0IHdpbGwgcmViaW5kIHN0YXJ0aW5nIHdpdGggdGhlIGZpcnN0IGNoaWxkIG9mIENhbnZhcy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFlvdSBjYW4gc2VlIHRoaXMgaGFwcGVuaW5nIHdoZW4gc2V0dGluZyBhIGJyZWFrcG9pbnQgaW4gU2NvcGVDb25maWd1cmF0b3Igd2hlcmUgY29udGFpbmVycyBhcmUgaW5pdGlhbGl6ZWQgd2l0aCBkcmFnICYgZHJvcDogb24gcGFnZSBsb2FkLCB0aGUgZmlyc3QgZWxlbWVudFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXMgYSBDYW52YXMgKGdvb2QpLCBidXQgYWZ0ZXIgaGF2aW5nIHNlbGVjdGVkIGFub3RoZXIgdGVtcGxhdGUsIHRoZSBmaXJzdCBlbGVtZW50IGlzICh0eXBpY2FsbHkpIGEgR3JpZCAoYmFkKS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNpbXBseSByZWNvbXBpbGluZyB0aGUgb3JjLWxheW91dC1lZGl0b3IgZGlyZWN0aXZlIHdpbGwgY2F1c2UgdGhlIGVudGlyZSB0aGluZyB0byBiZSBnZW5lcmF0ZWQsIHdoaWNoIHdvcmtzIGp1c3QgZmluZSBhcyB3ZWxsIChldmVuIHRob3VnaCBub3QgaXMgbmljZSBhcyBzaW1wbHkgbGV2ZXJhZ2luZyBtb2RlbCBiaW5kaW5nKS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxheW91dERlc2lnbmVySG9zdC5lZGl0b3IgPSB3aW5kb3cubGF5b3V0RWRpdG9yID0gbmV3IExheW91dEVkaXRvci5FZGl0b3IoZWRpdG9yLmNvbmZpZywgY2FudmFzRGF0YSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgdGVtcGxhdGUgPSBcIjxvcmMtbGF5b3V0LWVkaXRvclwiICsgXCIgbW9kZWw9J3dpbmRvdy5sYXlvdXRFZGl0b3InIC8+XCI7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgaHRtbCA9ICRjb21waWxlKHRlbXBsYXRlKSgkc2NvcGUpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJChcIi5sYXlvdXQtZWRpdG9yLWhvbGRlclwiKS5odG1sKGh0bWwpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kcm9vdC5lZGl0RWxlbWVudCA9IGZ1bmN0aW9uIChlbGVtZW50KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgaG9zdCA9ICRzY29wZS4kcm9vdC5sYXlvdXREZXNpZ25lckhvc3Q7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaG9zdC5lZGl0RWxlbWVudChlbGVtZW50KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kcm9vdC5hZGRFbGVtZW50ID0gZnVuY3Rpb24gKGNvbnRlbnRUeXBlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgaG9zdCA9ICRzY29wZS4kcm9vdC5sYXlvdXREZXNpZ25lckhvc3Q7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaG9zdC5hZGRFbGVtZW50KGNvbnRlbnRUeXBlKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLm9uKFwiY3V0IGNvcHkgcGFzdGVcIiwgZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIHRoZSBwc2V1ZG8gY2xpcGJvYXJkIHdhcyBhbHJlYWR5IGludm9rZWQgKHdoaWNoIGhhcHBlbnMgb24gdGhlIGZpcnN0IGNsaXBib2FyZFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gb3BlcmF0aW9uIGFmdGVyIHBhZ2UgbG9hZCBldmVuIGlmIG5hdGl2ZSBjbGlwYm9hcmQgc3VwcG9ydCBleGlzdHMpIHRoZW4gc2l0IHRoaXNcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9uZSBvcGVyYXRpb24gb3V0LCBidXQgbWFrZSBzdXJlIHdoYXRldmVyIGlzIG9uIHRoZSBwc2V1ZG8gY2xpcGJvYXJkIGdldHMgbWlncmF0ZWRcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRvIHRoZSBuYXRpdmUgY2xpcGJvYXJkIGZvciBzdWJzZXF1ZW50IG9wZXJhdGlvbnMuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY2xpcGJvYXJkLndhc0ludm9rZWQoKSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGUub3JpZ2luYWxFdmVudC5jbGlwYm9hcmREYXRhLnNldERhdGEoXCJ0ZXh0L3BsYWluXCIsIGNsaXBib2FyZC5nZXREYXRhKFwidGV4dC9wbGFpblwiKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZS5vcmlnaW5hbEV2ZW50LmNsaXBib2FyZERhdGEuc2V0RGF0YShcInRleHQvanNvblwiLCBjbGlwYm9hcmQuZ2V0RGF0YShcInRleHQvanNvblwiKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZvY3VzZWRFbGVtZW50ID0gJHNjb3BlLmVsZW1lbnQuZm9jdXNlZEVsZW1lbnQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEhZm9jdXNlZEVsZW1lbnQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLiRhcHBseShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKGUudHlwZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgXCJjb3B5XCI6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvY3VzZWRFbGVtZW50LmNvcHkoZS5vcmlnaW5hbEV2ZW50LmNsaXBib2FyZERhdGEpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwiY3V0XCI6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvY3VzZWRFbGVtZW50LmN1dChlLm9yaWdpbmFsRXZlbnQuY2xpcGJvYXJkRGF0YSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgXCJwYXN0ZVwiOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb2N1c2VkRWxlbWVudC5wYXN0ZShlLm9yaWdpbmFsRXZlbnQuY2xpcGJvYXJkRGF0YSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXZlbnQudHJpZ2dlcih7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiBcImxheW91dGVkaXRvcjplZGl0ZWRcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSEFDSzogV29ya2Fyb3VuZCBiZWNhdXNlIG9mIGhvdyBBbmd1bGFyIHRyZWF0cyB0aGUgRE9NIHdoZW4gZWxlbWVudHMgYXJlIHNoaWZ0ZWQgYXJvdW5kIC0gaW5wdXQgZm9jdXMgaXMgc29tZXRpbWVzIGxvc3QuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kYXBwbHkoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghISRzY29wZS5lbGVtZW50LmZvY3VzZWRFbGVtZW50KVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZWxlbWVudC5mb2N1c2VkRWxlbWVudC5zZXRJc0ZvY3VzZWQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LCAxMDApO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOYXRpdmUgY2xpcGJvYXJkIHN1cHBvcnQgb2J2aW91c2x5IGV4aXN0cywgc28gZGlzYWJsZSB0aGUgcGV1ZG8gY2xpcGJvYXJkIGZyb20gbm93IG9uLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpcGJvYXJkLmRpc2FibGUoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgXSxcclxuICAgICAgICAgICAgICAgIHRlbXBsYXRlVXJsOiBlbnZpcm9ubWVudC50ZW1wbGF0ZVVybChcIkVkaXRvclwiKSxcclxuICAgICAgICAgICAgICAgIHJlcGxhY2U6IHRydWUsXHJcbiAgICAgICAgICAgICAgICBsaW5rOiBmdW5jdGlvbiAoc2NvcGUsIGVsZW1lbnQpIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBObyBjbGlja3Mgc2hvdWxkIHByb3BhZ2F0ZSBmcm9tIHRoZSBUaW55TUNFIHRvb2xiYXJzLlxyXG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuZmluZChcIi5sYXlvdXQtdG9vbGJhci1jb250YWluZXJcIikuY2xpY2soZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAvLyBVbmZvY3VzIGFuZCB1bnNlbGVjdCBldmVyeXRoaW5nIG9uIGNsaWNrIG91dHNpZGUgb2YgY2FudmFzLlxyXG4gICAgICAgICAgICAgICAgICAgICQod2luZG93KS5jbGljayhmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBzY29wZS4kYXBwbHkoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGUuZWxlbWVudC5hY3RpdmVFbGVtZW50ID0gbnVsbDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjb3BlLmVsZW1lbnQuZm9jdXNlZEVsZW1lbnQgPSBudWxsO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfTtcclxuICAgICAgICB9XHJcbiAgICBdKTsiLCJhbmd1bGFyXHJcbiAgICAubW9kdWxlKFwiTGF5b3V0RWRpdG9yXCIpXHJcbiAgICAuZGlyZWN0aXZlKFwib3JjTGF5b3V0Q2FudmFzXCIsIFtcInNjb3BlQ29uZmlndXJhdG9yXCIsIFwiZW52aXJvbm1lbnRcIixcclxuICAgICAgICBmdW5jdGlvbiAoc2NvcGVDb25maWd1cmF0b3IsIGVudmlyb25tZW50KSB7XHJcbiAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICByZXN0cmljdDogXCJFXCIsXHJcbiAgICAgICAgICAgICAgICBzY29wZTogeyBlbGVtZW50OiBcIj1cIiB9LFxyXG4gICAgICAgICAgICAgICAgY29udHJvbGxlcjogW1wiJHNjb3BlXCIsIFwiJGVsZW1lbnRcIiwgXCIkYXR0cnNcIixcclxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoJHNjb3BlLCAkZWxlbWVudCwgJGF0dHJzKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjb3BlQ29uZmlndXJhdG9yLmNvbmZpZ3VyZUZvckVsZW1lbnQoJHNjb3BlLCAkZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjb3BlQ29uZmlndXJhdG9yLmNvbmZpZ3VyZUZvckNvbnRhaW5lcigkc2NvcGUsICRlbGVtZW50KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLnNvcnRhYmxlT3B0aW9uc1tcImF4aXNcIl0gPSBcInlcIjtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBdLFxyXG4gICAgICAgICAgICAgICAgdGVtcGxhdGVVcmw6IGVudmlyb25tZW50LnRlbXBsYXRlVXJsKFwiQ2FudmFzXCIpLFxyXG4gICAgICAgICAgICAgICAgcmVwbGFjZTogdHJ1ZVxyXG4gICAgICAgICAgICB9O1xyXG4gICAgICAgIH1cclxuICAgIF0pOyIsImFuZ3VsYXJcclxuICAgIC5tb2R1bGUoXCJMYXlvdXRFZGl0b3JcIilcclxuICAgIC5kaXJlY3RpdmUoXCJvcmNMYXlvdXRDaGlsZFwiLCBbXCIkY29tcGlsZVwiLFxyXG4gICAgICAgIGZ1bmN0aW9uICgkY29tcGlsZSkge1xyXG4gICAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICAgICAgcmVzdHJpY3Q6IFwiRVwiLFxyXG4gICAgICAgICAgICAgICAgc2NvcGU6IHsgZWxlbWVudDogXCI9XCIgfSxcclxuICAgICAgICAgICAgICAgIGxpbms6IGZ1bmN0aW9uIChzY29wZSwgZWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciB0ZW1wbGF0ZSA9IFwiPG9yYy1sYXlvdXQtXCIgKyBzY29wZS5lbGVtZW50LnR5cGUudG9Mb3dlckNhc2UoKSArIFwiIGVsZW1lbnQ9J2VsZW1lbnQnIC8+XCI7XHJcbiAgICAgICAgICAgICAgICAgICAgdmFyIGh0bWwgPSAkY29tcGlsZSh0ZW1wbGF0ZSkoc2NvcGUpO1xyXG4gICAgICAgICAgICAgICAgICAgICQoZWxlbWVudCkucmVwbGFjZVdpdGgoaHRtbCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH07XHJcbiAgICAgICAgfVxyXG4gICAgXSk7IiwiYW5ndWxhclxyXG4gICAgLm1vZHVsZShcIkxheW91dEVkaXRvclwiKVxyXG4gICAgLmRpcmVjdGl2ZShcIm9yY0xheW91dENvbHVtblwiLCBbXCIkY29tcGlsZVwiLCBcInNjb3BlQ29uZmlndXJhdG9yXCIsIFwiZW52aXJvbm1lbnRcIixcclxuICAgICAgICBmdW5jdGlvbiAoJGNvbXBpbGUsIHNjb3BlQ29uZmlndXJhdG9yLCBlbnZpcm9ubWVudCkge1xyXG4gICAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICAgICAgcmVzdHJpY3Q6IFwiRVwiLFxyXG4gICAgICAgICAgICAgICAgc2NvcGU6IHsgZWxlbWVudDogXCI9XCIgfSxcclxuICAgICAgICAgICAgICAgIGNvbnRyb2xsZXI6IFtcIiRzY29wZVwiLCBcIiRlbGVtZW50XCIsXHJcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCRzY29wZSwgJGVsZW1lbnQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGVDb25maWd1cmF0b3IuY29uZmlndXJlRm9yRWxlbWVudCgkc2NvcGUsICRlbGVtZW50KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGVDb25maWd1cmF0b3IuY29uZmlndXJlRm9yQ29udGFpbmVyKCRzY29wZSwgJGVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuc29ydGFibGVPcHRpb25zW1wiYXhpc1wiXSA9IFwieVwiO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIF0sXHJcbiAgICAgICAgICAgICAgICB0ZW1wbGF0ZVVybDogZW52aXJvbm1lbnQudGVtcGxhdGVVcmwoXCJDb2x1bW5cIiksXHJcbiAgICAgICAgICAgICAgICByZXBsYWNlOiB0cnVlLFxyXG4gICAgICAgICAgICAgICAgbGluazogZnVuY3Rpb24gKHNjb3BlLCBlbGVtZW50LCBhdHRycykge1xyXG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuZmluZChcIi5sYXlvdXQtY29sdW1uLXJlc2l6ZS1iYXJcIikuZHJhZ2dhYmxlKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgYXhpczogXCJ4XCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGhlbHBlcjogXCJjbG9uZVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICByZXZlcnQ6IHRydWUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0OiBmdW5jdGlvbiAoZSwgdWkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjb3BlLiRhcHBseShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGUuZWxlbWVudC5lZGl0b3IuaXNSZXNpemluZyA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgZHJhZzogZnVuY3Rpb24gKGUsIHVpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgY29sdW1uRWxlbWVudCA9IGVsZW1lbnQucGFyZW50KCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgY29sdW1uU2l6ZSA9IGNvbHVtbkVsZW1lbnQud2lkdGgoKSAvIHNjb3BlLmVsZW1lbnQud2lkdGg7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgY29ubmVjdEFkamFjZW50ID0gIWUuY3RybEtleTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICgkKGUudGFyZ2V0KS5oYXNDbGFzcyhcImxheW91dC1jb2x1bW4tcmVzaXplLWJhci1sZWZ0XCIpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGRlbHRhID0gdWkub2Zmc2V0LmxlZnQgLSBjb2x1bW5FbGVtZW50Lm9mZnNldCgpLmxlZnQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGRlbHRhIDwgLWNvbHVtblNpemUgJiYgc2NvcGUuZWxlbWVudC5jYW5FeHBhbmRMZWZ0KGNvbm5lY3RBZGphY2VudCkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGUuJGFwcGx5KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjb3BlLmVsZW1lbnQuZXhwYW5kTGVmdChjb25uZWN0QWRqYWNlbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoZGVsdGEgPiBjb2x1bW5TaXplICYmIHNjb3BlLmVsZW1lbnQuY2FuQ29udHJhY3RMZWZ0KGNvbm5lY3RBZGphY2VudCkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGUuJGFwcGx5KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjb3BlLmVsZW1lbnQuY29udHJhY3RMZWZ0KGNvbm5lY3RBZGphY2VudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKCQoZS50YXJnZXQpLmhhc0NsYXNzKFwibGF5b3V0LWNvbHVtbi1yZXNpemUtYmFyLXJpZ2h0XCIpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGRlbHRhID0gdWkub2Zmc2V0LmxlZnQgLSBjb2x1bW5FbGVtZW50LndpZHRoKCkgLSBjb2x1bW5FbGVtZW50Lm9mZnNldCgpLmxlZnQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGRlbHRhID4gY29sdW1uU2l6ZSAmJiBzY29wZS5lbGVtZW50LmNhbkV4cGFuZFJpZ2h0KGNvbm5lY3RBZGphY2VudCkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGUuJGFwcGx5KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjb3BlLmVsZW1lbnQuZXhwYW5kUmlnaHQoY29ubmVjdEFkamFjZW50KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKGRlbHRhIDwgLWNvbHVtblNpemUgJiYgc2NvcGUuZWxlbWVudC5jYW5Db250cmFjdFJpZ2h0KGNvbm5lY3RBZGphY2VudCkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGUuJGFwcGx5KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjb3BlLmVsZW1lbnQuY29udHJhY3RSaWdodChjb25uZWN0QWRqYWNlbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBzdG9wOiBmdW5jdGlvbiAoZSwgdWkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjb3BlLiRhcHBseShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjb3BlLmVsZW1lbnQuZWRpdG9yLmlzUmVzaXppbmcgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH07XHJcbiAgICAgICAgfVxyXG4gICAgXSk7IiwiYW5ndWxhclxyXG4gICAgLm1vZHVsZShcIkxheW91dEVkaXRvclwiKVxyXG4gICAgLmRpcmVjdGl2ZShcIm9yY0xheW91dENvbnRlbnRcIiwgW1wiJHNjZVwiLCBcInNjb3BlQ29uZmlndXJhdG9yXCIsIFwiZW52aXJvbm1lbnRcIixcclxuICAgICAgICBmdW5jdGlvbiAoJHNjZSwgc2NvcGVDb25maWd1cmF0b3IsIGVudmlyb25tZW50KSB7XHJcbiAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICByZXN0cmljdDogXCJFXCIsXHJcbiAgICAgICAgICAgICAgICBzY29wZTogeyBlbGVtZW50OiBcIj1cIiB9LFxyXG4gICAgICAgICAgICAgICAgY29udHJvbGxlcjogW1wiJHNjb3BlXCIsIFwiJGVsZW1lbnRcIixcclxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoJHNjb3BlLCAkZWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBzY29wZUNvbmZpZ3VyYXRvci5jb25maWd1cmVGb3JFbGVtZW50KCRzY29wZSwgJGVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3ZlcndyaXRlIHRoZSBzZXRIdG1sIGZ1bmN0aW9uIHNvIHRoYXQgd2UgY2FuIHVzZSB0aGUgJHNjZSBzZXJ2aWNlIHRvIHRydXN0IHRoZSBodG1sIChhbmQgbm90IGhhdmUgdGhlIGh0bWwgYmluZGluZyBzdHJpcCBjZXJ0YWluIHRhZ3MpLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZWxlbWVudC5zZXRIdG1sID0gZnVuY3Rpb24gKGh0bWwpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5lbGVtZW50Lmh0bWwgPSBodG1sO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmVsZW1lbnQuaHRtbFVuc2FmZSA9ICRzY2UudHJ1c3RBc0h0bWwoaHRtbCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZWxlbWVudC5zZXRIdG1sKCRzY29wZS5lbGVtZW50Lmh0bWwpO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIF0sXHJcbiAgICAgICAgICAgICAgICB0ZW1wbGF0ZVVybDogZW52aXJvbm1lbnQudGVtcGxhdGVVcmwoXCJDb250ZW50XCIpLFxyXG4gICAgICAgICAgICAgICAgcmVwbGFjZTogdHJ1ZVxyXG4gICAgICAgICAgICB9O1xyXG4gICAgICAgIH1cclxuICAgIF0pOyIsImFuZ3VsYXJcclxuICAgIC5tb2R1bGUoXCJMYXlvdXRFZGl0b3JcIilcclxuICAgIC5kaXJlY3RpdmUoXCJvcmNMYXlvdXRHcmlkXCIsIFtcIiRjb21waWxlXCIsIFwic2NvcGVDb25maWd1cmF0b3JcIiwgXCJlbnZpcm9ubWVudFwiLFxyXG4gICAgICAgIGZ1bmN0aW9uICgkY29tcGlsZSwgc2NvcGVDb25maWd1cmF0b3IsIGVudmlyb25tZW50KSB7XHJcbiAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICByZXN0cmljdDogXCJFXCIsXHJcbiAgICAgICAgICAgICAgICBzY29wZTogeyBlbGVtZW50OiBcIj1cIiB9LFxyXG4gICAgICAgICAgICAgICAgY29udHJvbGxlcjogW1wiJHNjb3BlXCIsIFwiJGVsZW1lbnRcIixcclxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoJHNjb3BlLCAkZWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBzY29wZUNvbmZpZ3VyYXRvci5jb25maWd1cmVGb3JFbGVtZW50KCRzY29wZSwgJGVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBzY29wZUNvbmZpZ3VyYXRvci5jb25maWd1cmVGb3JDb250YWluZXIoJHNjb3BlLCAkZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5zb3J0YWJsZU9wdGlvbnNbXCJheGlzXCJdID0gXCJ5XCI7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgXSxcclxuICAgICAgICAgICAgICAgIHRlbXBsYXRlVXJsOiBlbnZpcm9ubWVudC50ZW1wbGF0ZVVybChcIkdyaWRcIiksXHJcbiAgICAgICAgICAgICAgICByZXBsYWNlOiB0cnVlXHJcbiAgICAgICAgICAgIH07XHJcbiAgICAgICAgfVxyXG4gICAgXSk7IiwiYW5ndWxhclxyXG4gICAgLm1vZHVsZShcIkxheW91dEVkaXRvclwiKVxyXG4gICAgLmRpcmVjdGl2ZShcIm9yY0xheW91dFJvd1wiLCBbXCIkY29tcGlsZVwiLCBcInNjb3BlQ29uZmlndXJhdG9yXCIsIFwiZW52aXJvbm1lbnRcIixcclxuICAgICAgICBmdW5jdGlvbiAoJGNvbXBpbGUsIHNjb3BlQ29uZmlndXJhdG9yLCBlbnZpcm9ubWVudCkge1xyXG4gICAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICAgICAgcmVzdHJpY3Q6IFwiRVwiLFxyXG4gICAgICAgICAgICAgICAgc2NvcGU6IHsgZWxlbWVudDogXCI9XCIgfSxcclxuICAgICAgICAgICAgICAgIGNvbnRyb2xsZXI6IFtcIiRzY29wZVwiLCBcIiRlbGVtZW50XCIsXHJcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCRzY29wZSwgJGVsZW1lbnQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGVDb25maWd1cmF0b3IuY29uZmlndXJlRm9yRWxlbWVudCgkc2NvcGUsICRlbGVtZW50KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGVDb25maWd1cmF0b3IuY29uZmlndXJlRm9yQ29udGFpbmVyKCRzY29wZSwgJGVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuc29ydGFibGVPcHRpb25zW1wiYXhpc1wiXSA9IFwieFwiO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuc29ydGFibGVPcHRpb25zW1widWktZmxvYXRpbmdcIl0gPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIF0sXHJcbiAgICAgICAgICAgICAgICB0ZW1wbGF0ZVVybDogZW52aXJvbm1lbnQudGVtcGxhdGVVcmwoXCJSb3dcIiksXHJcbiAgICAgICAgICAgICAgICByZXBsYWNlOiB0cnVlXHJcbiAgICAgICAgICAgIH07XHJcbiAgICAgICAgfVxyXG4gICAgXSk7IiwiYW5ndWxhclxyXG4gICAgLm1vZHVsZShcIkxheW91dEVkaXRvclwiKVxyXG4gICAgLmRpcmVjdGl2ZShcIm9yY0xheW91dFBvcHVwXCIsIFtcclxuICAgICAgICBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICByZXN0cmljdDogXCJBXCIsXHJcbiAgICAgICAgICAgICAgICBsaW5rOiBmdW5jdGlvbiAoc2NvcGUsIGVsZW1lbnQsIGF0dHJzKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBvcHVwID0gJChlbGVtZW50KTtcclxuICAgICAgICAgICAgICAgICAgICB2YXIgdHJpZ2dlciA9IHBvcHVwLmNsb3Nlc3QoXCIubGF5b3V0LXBvcHVwLXRyaWdnZXJcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcmVudEVsZW1lbnQgPSBwb3B1cC5jbG9zZXN0KFwiLmxheW91dC1lbGVtZW50XCIpO1xyXG4gICAgICAgICAgICAgICAgICAgIHRyaWdnZXIuY2xpY2soZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBwb3B1cC50b2dnbGUoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBvcHVwLmlzKFwiOnZpc2libGVcIikpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVwLnBvc2l0aW9uKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBteTogYXR0cnMub3JjTGF5b3V0UG9wdXBNeSB8fCBcImxlZnQgdG9wXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXQ6IGF0dHJzLm9yY0xheW91dFBvcHVwQXQgfHwgXCJsZWZ0IGJvdHRvbSs0cHhcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvZjogdHJpZ2dlclxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3B1cC5maW5kKFwiaW5wdXRcIikuZmlyc3QoKS5mb2N1cygpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgcG9wdXAuY2xpY2soZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICBwYXJlbnRFbGVtZW50LmNsaWNrKGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVwLmhpZGUoKTtcclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICBwb3B1cC5rZXlkb3duKGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghZS5jdHJsS2V5ICYmICFlLnNoaWZ0S2V5ICYmICFlLmFsdEtleSAmJiBlLndoaWNoID09IDI3KSAvLyBFc2NcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVwLmhpZGUoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICBwb3B1cC5vbihcImN1dCBjb3B5IHBhc3RlXCIsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFsbG93IGNsaXBib2FyZCBvcGVyYXRpb25zIGluIHBvcHVwIHdpdGhvdXQgaW52b2tpbmcgY2xpcGJvYXJkIGV2ZW50IGhhbmRsZXJzIG9uIHBhcmVudCBlbGVtZW50LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9O1xyXG4gICAgICAgIH1cclxuICAgIF0pOyIsImFuZ3VsYXJcclxuICAgIC5tb2R1bGUoXCJMYXlvdXRFZGl0b3JcIilcclxuICAgIC5kaXJlY3RpdmUoXCJvcmNMYXlvdXRUb29sYm94XCIsIFtcIiRjb21waWxlXCIsIFwiZW52aXJvbm1lbnRcIixcclxuICAgICAgICBmdW5jdGlvbiAoJGNvbXBpbGUsIGVudmlyb25tZW50KSB7XHJcbiAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICByZXN0cmljdDogXCJFXCIsXHJcbiAgICAgICAgICAgICAgICBjb250cm9sbGVyOiBbXCIkc2NvcGVcIiwgXCIkZWxlbWVudFwiLFxyXG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uICgkc2NvcGUsICRlbGVtZW50KSB7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUucmVzZXRFbGVtZW50cyA9IGZ1bmN0aW9uICgpIHtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZ3JpZEVsZW1lbnRzID0gW1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExheW91dEVkaXRvci5HcmlkLmZyb20oe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94SWNvbjogXCJcXHVmMDBhXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hMYWJlbDogXCJHcmlkXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hEZXNjcmlwdGlvbjogXCJFbXB0eSBncmlkLlwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogW11cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUucm93RWxlbWVudHMgPSBbXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTGF5b3V0RWRpdG9yLlJvdy5mcm9tKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveEljb246IFwiXFx1ZjBjOVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94TGFiZWw6IFwiUm93ICgxIGNvbHVtbilcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveERlc2NyaXB0aW9uOiBcIlJvdyB3aXRoIDEgY29sdW1uLlwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogTGF5b3V0RWRpdG9yLkNvbHVtbi50aW1lcygxKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExheW91dEVkaXRvci5Sb3cuZnJvbSh7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hJY29uOiBcIlxcdWYwYzlcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveExhYmVsOiBcIlJvdyAoMiBjb2x1bW5zKVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94RGVzY3JpcHRpb246IFwiUm93IHdpdGggMiBjb2x1bW5zLlwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogTGF5b3V0RWRpdG9yLkNvbHVtbi50aW1lcygyKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExheW91dEVkaXRvci5Sb3cuZnJvbSh7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hJY29uOiBcIlxcdWYwYzlcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveExhYmVsOiBcIlJvdyAoMyBjb2x1bW5zKVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94RGVzY3JpcHRpb246IFwiUm93IHdpdGggMyBjb2x1bW5zLlwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogTGF5b3V0RWRpdG9yLkNvbHVtbi50aW1lcygzKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExheW91dEVkaXRvci5Sb3cuZnJvbSh7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hJY29uOiBcIlxcdWYwYzlcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveExhYmVsOiBcIlJvdyAoNCBjb2x1bW5zKVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94RGVzY3JpcHRpb246IFwiUm93IHdpdGggNCBjb2x1bW5zLlwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogTGF5b3V0RWRpdG9yLkNvbHVtbi50aW1lcyg0KVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExheW91dEVkaXRvci5Sb3cuZnJvbSh7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hJY29uOiBcIlxcdWYwYzlcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveExhYmVsOiBcIlJvdyAoNiBjb2x1bW5zKVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94RGVzY3JpcHRpb246IFwiUm93IHdpdGggNiBjb2x1bW5zLlwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogTGF5b3V0RWRpdG9yLkNvbHVtbi50aW1lcyg2KVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExheW91dEVkaXRvci5Sb3cuZnJvbSh7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hJY29uOiBcIlxcdWYwYzlcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveExhYmVsOiBcIlJvdyAoMTIgY29sdW1ucylcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveERlc2NyaXB0aW9uOiBcIlJvdyB3aXRoIDEyIGNvbHVtbnMuXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBMYXlvdXRFZGl0b3IuQ29sdW1uLnRpbWVzKDEyKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pLCBMYXlvdXRFZGl0b3IuUm93LmZyb20oe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94SWNvbjogXCJcXHVmMGM5XCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hMYWJlbDogXCJSb3cgKGVtcHR5KVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94RGVzY3JpcHRpb246IFwiRW1wdHkgcm93LlwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogW11cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuY29sdW1uRWxlbWVudHMgPSBbXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTGF5b3V0RWRpdG9yLkNvbHVtbi5mcm9tKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveEljb246IFwiXFx1ZjBkYlwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94TGFiZWw6IFwiQ29sdW1uXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hEZXNjcmlwdGlvbjogXCJFbXB0eSBjb2x1bW4uXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoOiAxLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvZmZzZXQ6IDAsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBbXVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5jYW52YXNFbGVtZW50cyA9IFtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMYXlvdXRFZGl0b3IuQ2FudmFzLmZyb20oe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b29sYm94SWNvbjogXCJcXHVmMDQ0XCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2xib3hMYWJlbDogXCJDYW52YXNcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbGJveERlc2NyaXB0aW9uOiBcIkVtcHR5IGNhbnZhcy5cIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hpbGRyZW46IFtdXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIF07XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmNvbnRlbnRFbGVtZW50Q2F0ZWdvcmllcyA9IF8oJHNjb3BlLmVsZW1lbnQuY29uZmlnLmNhdGVnb3JpZXMpLm1hcChmdW5jdGlvbiAoY2F0ZWdvcnkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lOiBjYXRlZ29yeS5uYW1lLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50czogXyhjYXRlZ29yeS5jb250ZW50VHlwZXMpLm1hcChmdW5jdGlvbiAoY29udGVudFR5cGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciB0eXBlID0gY29udGVudFR5cGUudHlwZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBmYWN0b3J5ID0gTGF5b3V0RWRpdG9yLmZhY3Rvcmllc1t0eXBlXSB8fCBMYXlvdXRFZGl0b3IuZmFjdG9yaWVzW1wiQ29udGVudFwiXTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpdGVtID0ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzVGVtcGxhdGVkOiBmYWxzZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250ZW50VHlwZTogY29udGVudFR5cGUuaWQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGVudFR5cGVMYWJlbDogY29udGVudFR5cGUubGFiZWwsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGVudFR5cGVDbGFzczogY29udGVudFR5cGUudHlwZUNsYXNzLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE6IG51bGwsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFzRWRpdG9yOiBjb250ZW50VHlwZS5oYXNFZGl0b3IsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaHRtbDogY29udGVudFR5cGUuaHRtbFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBlbGVtZW50ID0gZmFjdG9yeShpdGVtKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQudG9vbGJveEljb24gPSBjb250ZW50VHlwZS5pY29uIHx8IFwiXFx1ZjFjOVwiO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC50b29sYm94TGFiZWwgPSBjb250ZW50VHlwZS5sYWJlbDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQudG9vbGJveERlc2NyaXB0aW9uID0gY29udGVudFR5cGUuZGVzY3JpcHRpb247XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZWxlbWVudDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLnJlc2V0RWxlbWVudHMoKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5nZXRTb3J0YWJsZU9wdGlvbnMgPSBmdW5jdGlvbiAodHlwZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGVkaXRvcklkID0gJGVsZW1lbnQuY2xvc2VzdChcIi5sYXlvdXQtZWRpdG9yXCIpLmF0dHIoXCJpZFwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBwYXJlbnRDbGFzc2VzO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHBsYWNlaG9sZGVyQ2xhc3NlcztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBmbG9hdGluZyA9IGZhbHNlO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN3aXRjaCAodHlwZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgXCJHcmlkXCI6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmVudENsYXNzZXMgPSBbXCIubGF5b3V0LWNhbnZhc1wiLCBcIi5sYXlvdXQtY29sdW1uXCIsIFwiLmxheW91dC1jb21tb24taG9sZGVyXCJdO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlckNsYXNzZXMgPSBcImxheW91dC1lbGVtZW50IGxheW91dC1jb250YWluZXIgbGF5b3V0LWdyaWQgdWktc29ydGFibGUtcGxhY2Vob2xkZXJcIjtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcIlJvd1wiOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRDbGFzc2VzID0gW1wiLmxheW91dC1ncmlkXCJdO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlckNsYXNzZXMgPSBcImxheW91dC1lbGVtZW50IGxheW91dC1jb250YWluZXIgbGF5b3V0LXJvdyByb3cgdWktc29ydGFibGUtcGxhY2Vob2xkZXJcIjtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcIkNvbHVtblwiOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRDbGFzc2VzID0gW1wiLmxheW91dC1yb3c6bm90KC5sYXlvdXQtcm93LWZ1bGwpXCJdO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbGFjZWhvbGRlckNsYXNzZXMgPSBcImxheW91dC1lbGVtZW50IGxheW91dC1jb250YWluZXIgbGF5b3V0LWNvbHVtbiB1aS1zb3J0YWJsZS1wbGFjZWhvbGRlclwiO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbG9hdGluZyA9IHRydWU7IC8vIFRvIGVuc3VyZSBhIHNtb290aCBob3Jpem9udGFsLWxpc3QgcmVvcmRlcmluZy4gaHR0cHM6Ly9naXRodWIuY29tL2FuZ3VsYXItdWkvdWktc29ydGFibGUjZmxvYXRpbmdcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcIkNvbnRlbnRcIjpcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50Q2xhc3NlcyA9IFtcIi5sYXlvdXQtY2FudmFzXCIsIFwiLmxheW91dC1jb2x1bW5cIiwgXCIubGF5b3V0LWNvbW1vbi1ob2xkZXJcIl07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyQ2xhc3NlcyA9IFwibGF5b3V0LWVsZW1lbnQgbGF5b3V0LWNvbnRlbnQgdWktc29ydGFibGUtcGxhY2Vob2xkZXJcIjtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcIkNhbnZhc1wiOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRDbGFzc2VzID0gW1wiLmxheW91dC1jYW52YXNcIiwgXCIubGF5b3V0LWNvbHVtblwiLCBcIi5sYXlvdXQtY29tbW9uLWhvbGRlclwiXTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXJDbGFzc2VzID0gXCJsYXlvdXQtZWxlbWVudCBsYXlvdXQtY29udGFpbmVyIGxheW91dC1ncmlkIHVpLXNvcnRhYmxlLXBsYWNlaG9sZGVyXCI7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Vyc29yOiBcIm1vdmVcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25uZWN0V2l0aDogXyhwYXJlbnRDbGFzc2VzKS5tYXAoZnVuY3Rpb24gKGUpIHsgcmV0dXJuIFwiI1wiICsgZWRpdG9ySWQgKyBcIiBcIiArIGUgKyBcIjpub3QoLmxheW91dC1jb250YWluZXItc2VhbGVkKSA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1jaGlsZHJlblwiOyB9KS5qb2luKFwiLCBcIiksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI6IHBsYWNlaG9sZGVyQ2xhc3NlcyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcInVpLWZsb2F0aW5nXCI6IGZsb2F0aW5nLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlbHBlcjogXCJjbG9uZVwiLCAvLyBXZSBjbG9uZSB0aGUgZWxlbWVudCBhbmQgd2UgYXBwZW5kIGl0IHRvIHRoZSBib2R5IGJlY2F1c2UgdGhlIGNvbnRhaW5lciBvdmVyZmxvdyBpcyBzZXQgdG8gYXV0byAoc2VlOiBBc3NldHNcXExlc3NcXExheW91dEVkaXRvclxcVG9vbGJveC5sZXNzKSBhbmQgb3RoZXJ3aXNlIGl0IGNvdWxkIG5vdCBiZSBtb3ZlZCB3aXRoIGRyYWcmZHJvcFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFwcGVuZFRvOiBcImJvZHlcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcmVhdGU6IGZ1bmN0aW9uIChlLCB1aSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLnRhcmdldC5pc1Rvb2xib3ggPSB0cnVlOyAvLyBXaWxsIGluZGljYXRlIHRvIGNvbm5lY3RlZCBzb3J0YWJsZXMgdGhhdCBkcm9wcGVkIGl0ZW1zIHdlcmUgc2VudCBmcm9tIHRvb2xib3guXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydDogZnVuY3Rpb24gKGUsIHVpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kYXBwbHkoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmVsZW1lbnQuaXNEcmFnZ2luZyA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RvcDogZnVuY3Rpb24gKGUsIHVpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS4kYXBwbHkoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmVsZW1lbnQuaXNEcmFnZ2luZyA9IGZhbHNlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLnJlc2V0RWxlbWVudHMoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdmVyOiBmdW5jdGlvbiAoZSwgdWkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLiRhcHBseShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUuZWxlbWVudC5jYW52YXMuc2V0SXNEcm9wVGFyZ2V0KGZhbHNlKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBsYXlvdXRJc0NvbGxhcHNlZENvb2tpZU5hbWUgPSBcImxheW91dFRvb2xib3hDYXRlZ29yeV9MYXlvdXRfSXNDb2xsYXBzZWRcIjtcclxuICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmxheW91dElzQ29sbGFwc2VkID0gJC5jb29raWUobGF5b3V0SXNDb2xsYXBzZWRDb29raWVOYW1lKSA9PT0gXCJ0cnVlXCI7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUudG9nZ2xlTGF5b3V0SXNDb2xsYXBzZWQgPSBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmxheW91dElzQ29sbGFwc2VkID0gISRzY29wZS5sYXlvdXRJc0NvbGxhcHNlZDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuY29va2llKGxheW91dElzQ29sbGFwc2VkQ29va2llTmFtZSwgJHNjb3BlLmxheW91dElzQ29sbGFwc2VkLCB7IGV4cGlyZXM6IDM2NSB9KTsgLy8gUmVtZW1iZXIgY29sbGFwc2VkIHN0YXRlIGZvciBhIHllYXIuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIF0sXHJcbiAgICAgICAgICAgICAgICB0ZW1wbGF0ZVVybDogZW52aXJvbm1lbnQudGVtcGxhdGVVcmwoXCJUb29sYm94XCIpLFxyXG4gICAgICAgICAgICAgICAgcmVwbGFjZTogdHJ1ZVxyXG4gICAgICAgICAgICB9O1xyXG4gICAgICAgIH1cclxuICAgIF0pOyIsImFuZ3VsYXJcclxuICAgIC5tb2R1bGUoXCJMYXlvdXRFZGl0b3JcIilcclxuICAgIC5kaXJlY3RpdmUoXCJvcmNMYXlvdXRUb29sYm94R3JvdXBcIiwgW1wiJGNvbXBpbGVcIiwgXCJlbnZpcm9ubWVudFwiLFxyXG4gICAgICAgIGZ1bmN0aW9uICgkY29tcGlsZSwgZW52aXJvbm1lbnQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICAgIHJlc3RyaWN0OiBcIkVcIixcclxuICAgICAgICAgICAgICAgIHNjb3BlOiB7IGNhdGVnb3J5OiBcIj1cIiB9LFxyXG4gICAgICAgICAgICAgICAgY29udHJvbGxlcjogW1wiJHNjb3BlXCIsIFwiJGVsZW1lbnRcIixcclxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoJHNjb3BlLCAkZWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNDb2xsYXBzZWRDb29raWVOYW1lID0gXCJsYXlvdXRUb29sYm94Q2F0ZWdvcnlfXCIgKyAkc2NvcGUuY2F0ZWdvcnkubmFtZSArIFwiX0lzQ29sbGFwc2VkXCI7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICRzY29wZS5pc0NvbGxhcHNlZCA9ICQuY29va2llKGlzQ29sbGFwc2VkQ29va2llTmFtZSkgPT09IFwidHJ1ZVwiO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAkc2NvcGUudG9nZ2xlSXNDb2xsYXBzZWQgPSBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJHNjb3BlLmlzQ29sbGFwc2VkID0gISRzY29wZS5pc0NvbGxhcHNlZDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuY29va2llKGlzQ29sbGFwc2VkQ29va2llTmFtZSwgJHNjb3BlLmlzQ29sbGFwc2VkLCB7IGV4cGlyZXM6IDM2NSB9KTsgLy8gUmVtZW1iZXIgY29sbGFwc2VkIHN0YXRlIGZvciBhIHllYXIuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIF0sXHJcbiAgICAgICAgICAgICAgICB0ZW1wbGF0ZVVybDogZW52aXJvbm1lbnQudGVtcGxhdGVVcmwoXCJUb29sYm94R3JvdXBcIiksXHJcbiAgICAgICAgICAgICAgICByZXBsYWNlOiB0cnVlXHJcbiAgICAgICAgICAgIH07XHJcbiAgICAgICAgfVxyXG4gICAgXSk7Il19 diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.min.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.min.js index c6d7ab6154e..b420db8fd5d 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.min.js +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.min.js @@ -1 +1 @@ -angular.module("LayoutEditor",["ngSanitize","ngResource","ui.sortable"]);var LayoutEditor;!function(e){var t=function(){var e=this;this._clipboardData={},this._isDisabled=!1,this._wasInvoked=!1,this.setData=function(t,o){e._clipboardData[t]=o,e._wasInvoked=!0},this.getData=function(t){return e._wasInvoked=!0,e._clipboardData[t]},this.disable=function(){e._isDisabled=!0,e._wasInvoked=!1,e._clipboardData={}},this.isDisabled=function(){return e._isDisabled},this.wasInvoked=function(){return e._wasInvoked}};e.Clipboard=new t,angular.module("LayoutEditor").factory("clipboard",[function(){return{setData:e.Clipboard.setData,getData:e.Clipboard.getData,disable:e.Clipboard.disable,isDisabled:e.Clipboard.isDisabled,wasInvoked:e.Clipboard.wasInvoked}}])}(LayoutEditor||(LayoutEditor={})),angular.module("LayoutEditor").factory("scopeConfigurator",["$timeout","clipboard",function(e,t){return{configureForElement:function(e,o){o.find(".layout-panel").click(function(e){e.stopPropagation()}),o.parent().keydown(function(n){var l=!1,a=!1,r=e.element;if(!r.editor.isDragging){if(!t.isDisabled()){var i=r.editor.focusedElement;if(i&&n.ctrlKey)switch(n.which){case 67:i.copy(t);break;case 88:i.cut(t);break;case 86:i.paste(t)}}if(n.ctrlKey||n.shiftKey||n.altKey||46!=n.which?n.ctrlKey||n.shiftKey||n.altKey||32!=n.which&&27!=n.which||(o.find(".layout-panel-action-properties").first().click(),l=!0):(e.delete(r),l=!0),r.hasEditor&&(n.ctrlKey||n.shiftKey||n.altKey||13!=n.which||(o.find(".layout-panel-action-edit").first().click(),l=!0)),r.children&&(n.ctrlKey||n.shiftKey||!n.altKey||40!=n.which||(r.children.length>0&&r.children[0].setIsFocused(),l=!0),"Column"==r.type)){var c=!n.ctrlKey;37==n.which?(n.altKey&&r.expandLeft(c),n.shiftKey&&r.contractRight(c),l=!0):39==n.which&&(n.altKey&&r.contractLeft(c),n.shiftKey&&r.expandRight(c),l=!0)}r.parent&&(n.altKey&&38==n.which&&(r.parent.setIsFocused(),l=!0),"Row"==r.parent.type?n.ctrlKey||n.shiftKey||n.altKey||37!=n.which?n.ctrlKey||n.shiftKey||n.altKey||39!=n.which?!n.ctrlKey||n.shiftKey||n.altKey||37!=n.which?!n.ctrlKey||n.shiftKey||n.altKey||39!=n.which||(r.moveDown(),l=!0):(r.moveUp(),a=!0,l=!0):(r.parent.moveFocusNextChild(r),l=!0):(r.parent.moveFocusPrevChild(r),l=!0):n.ctrlKey||n.shiftKey||n.altKey||38!=n.which?n.ctrlKey||n.shiftKey||n.altKey||40!=n.which?!n.ctrlKey||n.shiftKey||n.altKey||38!=n.which?!n.ctrlKey||n.shiftKey||n.altKey||40!=n.which||(r.moveDown(),l=!0):(r.moveUp(),a=!0,l=!0):(r.parent.moveFocusNextChild(r),l=!0):(r.parent.moveFocusPrevChild(r),l=!0)),l&&n.preventDefault(),n.stopPropagation(),e.$apply(),a&&window.setTimeout(function(){e.$apply(function(){r.editor.focusedElement.setIsFocused()})},100)}}),e.element.setIsFocusedEventHandlers.push(function(){o.parent().focus()}),e.delete=function(e){e.delete()},e.element.hasEditor&&(e.edit=function(){e.$root.editElement(e.element).then(function(t){e.$apply(function(){t.cancel||(e.element.data=t.element.data,e.element.applyElementEditorModel(t.elementEditorModel),e.element.setHtml&&e.element.setHtml(t.element.html))})})})},configureForContainer:function(t,o){var n=t.element;t.getShowChildrenPlaceholder=function(){return 0===t.element.children.length&&!t.element.getIsDropTarget()},t.sortableOptions={cursor:"move",delay:150,disabled:n.getIsSealed(),distance:5,start:function(e,o){t.$apply(function(){n.setIsDropTarget(!0),n.editor.isDragging=!0}),o.placeholder.height(o.item.height()-4),o.placeholder.css("min-height",0)},stop:function(e,o){t.$apply(function(){n.editor.isDragging=!1,n.setIsDropTarget(!1)})},over:function(t,l){l.sender&&l.sender[0].isToolbox&&(l.sender[0].dropTargetTimeout&&(e.cancel(l.sender[0].dropTargetTimeout),l.sender[0].dropTargetTimeout=null),e(function(){if("Row"==n.type){var e=n.editor.dropTargetElement;e&&"Row"==e.type&&e.rollbackAddColumn()}n.setIsDropTarget(!1)}),l.sender[0].dropTargetTimeout=e(function(){if("Row"==n.type){var e=l.item.sortable.model,t=Math.floor(12/(n.children.length+1));e.width=t,e.offset=0,n.beginAddColumn(t);var a=_.max(_(o.find("> .layout-children > .layout-column:not(.ui-sortable-placeholder)")).map(function(e){return $(e).height()}));for(i=1;i<=12;i++)l.placeholder.removeClass("col-xs-"+i);l.placeholder.addClass("col-xs-"+e.width),a>0?(l.placeholder.height(a),l.placeholder.css("min-height",0)):(l.placeholder.height(0),l.placeholder.css("min-height",""))}n.setIsDropTarget(!0)},150))},receive:function(o,l){l.sender&&l.sender[0].isToolbox&&t.$apply(function(){var o=l.item.sortable.model;o&&("Row"==n.type&&n.commitAddColumn(),o.setEditor(n.editor),o.setParent(n),o.hasEditor&&t.$root.editElement(o).then(function(t){t.cancel||(o.data=t.element.data,o.applyElementEditorModel(t.elementEditorModel),o.setHtml&&o.setHtml(t.element.html)),e(function(){t.cancel?o.delete():o.setIsFocused(),n.setIsDropTarget(!1)})})),e(function(){n.setIsDropTarget(!1),o&&o.setIsFocused()})})}},t.click=function(e,t){e.editor.isDragging||e.setIsFocused(),t.stopPropagation()},t.getClasses=function(e){var t=["layout-element"];return e.children&&(t.push("layout-container"),e.getIsSealed()&&t.push("layout-container-sealed")),t.push("layout-"+e.type.toLowerCase()),e.dropTargetClass&&t.push(e.dropTargetClass),"Row"==e.type&&(t.push("row"),e.canAddColumn()||t.push("layout-row-full")),"Column"==e.type&&(t.push("col-xs-"+e.width),t.push("col-xs-offset-"+e.offset)),"Content"==e.type&&t.push("layout-content-"+e.contentTypeClass),e.getIsActive()&&t.push("layout-element-active"),e.getIsFocused()&&t.push("layout-element-focused"),e.getIsSelected()&&t.push("layout-element-selected"),e.getIsDropTarget()&&t.push("layout-element-droptarget"),e.isTemplated&&t.push("layout-element-templated"),t}}}}]),angular.module("LayoutEditor").directive("orcLayoutEditor",["environment",function(environment){return{restrict:"E",scope:{},controller:["$scope","$element","$attrs","$compile","clipboard",function($scope,$element,$attrs,$compile,clipboard){if(!$attrs.model)throw new Error("The 'model' attribute must evaluate to a LayoutEditor.Editor object.");$scope.element=eval($attrs.model),$scope.click=function(e,t){e.editor.isDragging||e.setIsFocused(),t.stopPropagation()},$scope.getClasses=function(e){var t=["layout-element","layout-container","layout-canvas"];return e.getIsActive()&&t.push("layout-element-active"),e.getIsFocused()&&t.push("layout-element-focused"),e.getIsSelected()&&t.push("layout-element-selected"),e.getIsDropTarget()&&t.push("layout-element-droptarget"),e.isTemplated&&t.push("layout-element-templated"),t};var layoutDesignerHost=$(".layout-designer").data("layout-designer-host");$scope.$root.layoutDesignerHost=layoutDesignerHost,layoutDesignerHost.element.on("replacecanvas",function(e,t){var o=$scope.element,n={data:t.canvas.data,htmlId:t.canvas.htmlId,htmlClass:t.canvas.htmlClass,htmlStyle:t.canvas.htmlStyle,isTemplated:t.canvas.isTemplated,children:t.canvas.children};layoutDesignerHost.editor=window.layoutEditor=new LayoutEditor.Editor(o.config,n);var l="",a=$compile(l)($scope);$(".layout-editor-holder").html(a)}),$scope.$root.editElement=function(e){var t=$scope.$root.layoutDesignerHost;return t.editElement(e)},$scope.$root.addElement=function(e){var t=$scope.$root.layoutDesignerHost;return t.addElement(e)},$(document).on("cut copy paste",function(e){if(clipboard.wasInvoked())e.originalEvent.clipboardData.setData("text/plain",clipboard.getData("text/plain")),e.originalEvent.clipboardData.setData("text/json",clipboard.getData("text/json")),e.preventDefault();else{var t=$scope.element.focusedElement;t&&($scope.$apply(function(){switch(e.type){case"copy":t.copy(e.originalEvent.clipboardData);break;case"cut":t.cut(e.originalEvent.clipboardData);break;case"paste":t.paste(e.originalEvent.clipboardData)}}),window.setTimeout(function(){$scope.$apply(function(){$scope.element.focusedElement&&$scope.element.focusedElement.setIsFocused()})},100),e.preventDefault())}clipboard.disable()})}],templateUrl:environment.templateUrl("Editor"),replace:!0,link:function(e,t){t.find(".layout-toolbar-container").click(function(e){e.stopPropagation()}),$(window).click(function(t){e.$apply(function(){e.element.activeElement=null,e.element.focusedElement=null})})}}}]),angular.module("LayoutEditor").directive("orcLayoutCanvas",["scopeConfigurator","environment",function(e,t){return{restrict:"E",scope:{element:"="},controller:["$scope","$element","$attrs",function(t,o,n){e.configureForElement(t,o),e.configureForContainer(t,o),t.sortableOptions.axis="y"}],templateUrl:t.templateUrl("Canvas"),replace:!0}}]),angular.module("LayoutEditor").directive("orcLayoutChild",["$compile",function(e){return{restrict:"E",scope:{element:"="},link:function(t,o){var n="",l=e(n)(t);$(o).replaceWith(l)}}}]),angular.module("LayoutEditor").directive("orcLayoutColumn",["$compile","scopeConfigurator","environment",function(e,t,o){return{restrict:"E",scope:{element:"="},controller:["$scope","$element",function(e,o){t.configureForElement(e,o),t.configureForContainer(e,o),e.sortableOptions.axis="y"}],templateUrl:o.templateUrl("Column"),replace:!0,link:function(e,t,o){t.find(".layout-column-resize-bar").draggable({axis:"x",helper:"clone",revert:!0,start:function(t,o){e.$apply(function(){e.element.editor.isResizing=!0})},drag:function(o,n){var l=t.parent(),a=l.width()/e.element.width,r=!o.ctrlKey;if($(o.target).hasClass("layout-column-resize-bar-left")){var i=n.offset.left-l.offset().left;i<-a&&e.element.canExpandLeft(r)?e.$apply(function(){e.element.expandLeft(r)}):i>a&&e.element.canContractLeft(r)&&e.$apply(function(){e.element.contractLeft(r)})}else if($(o.target).hasClass("layout-column-resize-bar-right")){var i=n.offset.left-l.width()-l.offset().left;i>a&&e.element.canExpandRight(r)?e.$apply(function(){e.element.expandRight(r)}):i<-a&&e.element.canContractRight(r)&&e.$apply(function(){e.element.contractRight(r)})}},stop:function(t,o){e.$apply(function(){e.element.editor.isResizing=!1})}})}}}]),angular.module("LayoutEditor").directive("orcLayoutContent",["$sce","scopeConfigurator","environment",function(e,t,o){return{restrict:"E",scope:{element:"="},controller:["$scope","$element",function(o,n){t.configureForElement(o,n),o.element.setHtml=function(t){o.element.html=t,o.element.htmlUnsafe=e.trustAsHtml(t)},o.element.setHtml(o.element.html)}],templateUrl:o.templateUrl("Content"),replace:!0}}]),angular.module("LayoutEditor").directive("orcLayoutGrid",["$compile","scopeConfigurator","environment",function(e,t,o){return{restrict:"E",scope:{element:"="},controller:["$scope","$element",function(e,o){t.configureForElement(e,o),t.configureForContainer(e,o),e.sortableOptions.axis="y"}],templateUrl:o.templateUrl("Grid"),replace:!0}}]),angular.module("LayoutEditor").directive("orcLayoutRow",["$compile","scopeConfigurator","environment",function(e,t,o){return{restrict:"E",scope:{element:"="},controller:["$scope","$element",function(e,o){t.configureForElement(e,o),t.configureForContainer(e,o),e.sortableOptions.axis="x",e.sortableOptions["ui-floating"]=!0}],templateUrl:o.templateUrl("Row"),replace:!0}}]),angular.module("LayoutEditor").directive("orcLayoutPopup",[function(){return{restrict:"A",link:function(e,t,o){var n=$(t),l=n.closest(".layout-popup-trigger"),a=n.closest(".layout-element");l.click(function(){n.toggle(),n.is(":visible")&&(n.position({my:o.orcLayoutPopupMy||"left top",at:o.orcLayoutPopupAt||"left bottom+4px",of:l}),n.find("input").first().focus())}),n.click(function(e){e.stopPropagation()}),a.click(function(e){n.hide()}),n.keydown(function(e){e.ctrlKey||e.shiftKey||e.altKey||27!=e.which||n.hide(),e.stopPropagation()}),n.on("cut copy paste",function(e){e.stopPropagation()})}}}]),angular.module("LayoutEditor").directive("orcLayoutToolbox",["$compile","environment",function(e,t){return{restrict:"E",controller:["$scope","$element",function(e,t){e.resetElements=function(){e.gridElements=[LayoutEditor.Grid.from({toolboxIcon:"",toolboxLabel:"Grid",toolboxDescription:"Empty grid.",children:[]})],e.rowElements=[LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (1 column)",toolboxDescription:"Row with 1 column.",children:LayoutEditor.Column.times(1)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (2 columns)",toolboxDescription:"Row with 2 columns.",children:LayoutEditor.Column.times(2)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (3 columns)",toolboxDescription:"Row with 3 columns.",children:LayoutEditor.Column.times(3)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (4 columns)",toolboxDescription:"Row with 4 columns.",children:LayoutEditor.Column.times(4)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (6 columns)",toolboxDescription:"Row with 6 columns.",children:LayoutEditor.Column.times(6)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (12 columns)",toolboxDescription:"Row with 12 columns.",children:LayoutEditor.Column.times(12)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (empty)",toolboxDescription:"Empty row.",children:[]})],e.columnElements=[LayoutEditor.Column.from({toolboxIcon:"",toolboxLabel:"Column",toolboxDescription:"Empty column.",width:1,offset:0,children:[]})],e.canvasElements=[LayoutEditor.Canvas.from({toolboxIcon:"",toolboxLabel:"Canvas",toolboxDescription:"Empty canvas.",children:[]})],e.contentElementCategories=_(e.element.config.categories).map(function(e){return{name:e.name,elements:_(e.contentTypes).map(function(e){var t=e.type,o=LayoutEditor.factories[t]||LayoutEditor.factories.Content,n={isTemplated:!1,contentType:e.id,contentTypeLabel:e.label,contentTypeClass:e.typeClass,data:null,hasEditor:e.hasEditor,html:e.html},l=o(n);return l.toolboxIcon=e.icon||"",l.toolboxLabel=e.label,l.toolboxDescription=e.description,l})}})},e.resetElements(),e.getSortableOptions=function(o){var n,l,a=t.closest(".layout-editor").attr("id"),r=!1;switch(o){case"Grid":n=[".layout-canvas",".layout-column",".layout-common-holder"],l="layout-element layout-container layout-grid ui-sortable-placeholder";break;case"Row":n=[".layout-grid"],l="layout-element layout-container layout-row row ui-sortable-placeholder";break;case"Column":n=[".layout-row:not(.layout-row-full)"],l="layout-element layout-container layout-column ui-sortable-placeholder",r=!0;break;case"Content":n=[".layout-canvas",".layout-column",".layout-common-holder"],l="layout-element layout-content ui-sortable-placeholder";break;case"Canvas":n=[".layout-canvas",".layout-column",".layout-common-holder"],l="layout-element layout-container layout-grid ui-sortable-placeholder"}return{cursor:"move",connectWith:_(n).map(function(e){return"#"+a+" "+e+":not(.layout-container-sealed) > .layout-element-wrapper > .layout-children"}).join(", "),placeholder:l,"ui-floating":r,create:function(e,t){e.target.isToolbox=!0},start:function(t,o){e.$apply(function(){e.element.isDragging=!0})},stop:function(t,o){e.$apply(function(){e.element.isDragging=!1,e.resetElements()})},over:function(t,o){e.$apply(function(){e.element.canvas.setIsDropTarget(!1)})}}};var o="layoutToolboxCategory_Layout_IsCollapsed";e.layoutIsCollapsed="true"===$.cookie(o),e.toggleLayoutIsCollapsed=function(t){e.layoutIsCollapsed=!e.layoutIsCollapsed,$.cookie(o,e.layoutIsCollapsed,{expires:365}),t.preventDefault(),t.stopPropagation()}}],templateUrl:t.templateUrl("Toolbox"),replace:!0,link:function(e,t){var o=t.find(".layout-toolbox");$(window).on("resize scroll",function(e){var n=t.parent().find(".layout-canvas"),l=!!n&&n.height()>o.height(),a=$(window).scrollTop();l&&a>t.offset().top+t.height()-o.height()?(o.addClass("sticky-bottom"),o.removeClass("sticky-top")):l&&a>t.offset().top?(o.addClass("sticky-top"),o.removeClass("sticky-bottom")):(o.removeClass("sticky-top"),o.removeClass("sticky-bottom"))})}}}]),angular.module("LayoutEditor").directive("orcLayoutToolboxGroup",["$compile","environment",function(e,t){return{restrict:"E",scope:{category:"="},controller:["$scope","$element",function(e,t){var o="layoutToolboxCategory_"+e.category.name+"_IsCollapsed";e.isCollapsed="true"===$.cookie(o),e.toggleIsCollapsed=function(t){e.isCollapsed=!e.isCollapsed,$.cookie(o,e.isCollapsed,{expires:365}),t.preventDefault(),t.stopPropagation()}}],templateUrl:t.templateUrl("ToolboxGroup"),replace:!0}}]); +angular.module("LayoutEditor",["ngSanitize","ngResource","ui.sortable"]);var LayoutEditor;!function(e){var t=function(){var e=this;this._clipboardData={},this._isDisabled=!1,this._wasInvoked=!1,this.setData=function(t,o){e._clipboardData[t]=o,e._wasInvoked=!0},this.getData=function(t){return e._wasInvoked=!0,e._clipboardData[t]},this.disable=function(){e._isDisabled=!0,e._wasInvoked=!1,e._clipboardData={}},this.isDisabled=function(){return e._isDisabled},this.wasInvoked=function(){return e._wasInvoked}};e.Clipboard=new t,angular.module("LayoutEditor").factory("clipboard",[function(){return{setData:e.Clipboard.setData,getData:e.Clipboard.getData,disable:e.Clipboard.disable,isDisabled:e.Clipboard.isDisabled,wasInvoked:e.Clipboard.wasInvoked}}])}(LayoutEditor||(LayoutEditor={})),angular.module("LayoutEditor").factory("scopeConfigurator",["$timeout","clipboard",function(e,t){return{configureForElement:function(e,o){o.find(".layout-panel").click(function(e){e.stopPropagation()}),o.parent().keydown(function(n){var l=!1,a=!1,r=e.element;if(!r.editor.isDragging){if(!t.isDisabled()){var i=r.editor.focusedElement;if(i&&n.ctrlKey)switch(n.which){case 67:i.copy(t);break;case 88:i.cut(t);break;case 86:i.paste(t)}}if(n.ctrlKey||n.shiftKey||n.altKey||46!=n.which?n.ctrlKey||n.shiftKey||n.altKey||32!=n.which&&27!=n.which||(o.find(".layout-panel-action-properties").first().click(),l=!0):(e.delete(r),l=!0),r.hasEditor&&(n.ctrlKey||n.shiftKey||n.altKey||13!=n.which||(o.find(".layout-panel-action-edit").first().click(),l=!0)),r.children&&(n.ctrlKey||n.shiftKey||!n.altKey||40!=n.which||(r.children.length>0&&r.children[0].setIsFocused(),l=!0),"Column"==r.type)){var c=!n.ctrlKey;37==n.which?(n.altKey&&r.expandLeft(c),n.shiftKey&&r.contractRight(c),l=!0):39==n.which&&(n.altKey&&r.contractLeft(c),n.shiftKey&&r.expandRight(c),l=!0)}r.parent&&(n.altKey&&38==n.which&&(r.parent.setIsFocused(),l=!0),"Row"==r.parent.type?n.ctrlKey||n.shiftKey||n.altKey||37!=n.which?n.ctrlKey||n.shiftKey||n.altKey||39!=n.which?!n.ctrlKey||n.shiftKey||n.altKey||37!=n.which?!n.ctrlKey||n.shiftKey||n.altKey||39!=n.which||(r.moveDown(),l=!0):(r.moveUp(),a=!0,l=!0):(r.parent.moveFocusNextChild(r),l=!0):(r.parent.moveFocusPrevChild(r),l=!0):n.ctrlKey||n.shiftKey||n.altKey||38!=n.which?n.ctrlKey||n.shiftKey||n.altKey||40!=n.which?!n.ctrlKey||n.shiftKey||n.altKey||38!=n.which?!n.ctrlKey||n.shiftKey||n.altKey||40!=n.which||(r.moveDown(),l=!0):(r.moveUp(),a=!0,l=!0):(r.parent.moveFocusNextChild(r),l=!0):(r.parent.moveFocusPrevChild(r),l=!0)),l&&n.preventDefault(),n.stopPropagation(),e.$apply(),a&&window.setTimeout(function(){e.$apply(function(){r.editor.focusedElement.setIsFocused()})},100)}}),e.element.setIsFocusedEventHandlers.push(function(){o.parent().focus()}),e.delete=function(e){e.delete(),$.event.trigger({type:"layouteditor:edited"})},e.element.hasEditor&&(e.edit=function(){e.$root.editElement(e.element).done(function(t){e.$apply(function(){t.cancel||(e.element.data=t.element.data,e.element.applyElementEditorModel(t.elementEditorModel),e.element.setHtml&&e.element.setHtml(t.element.html))})})})},configureForContainer:function(t,o){var n=t.element;t.getShowChildrenPlaceholder=function(){return 0===t.element.children.length&&!t.element.getIsDropTarget()},t.sortableOptions={cursor:"move",delay:150,disabled:n.getIsSealed(),distance:5,start:function(e,o){t.$apply(function(){n.setIsDropTarget(!0),n.editor.isDragging=!0}),o.placeholder.height(o.item.height()-4),o.placeholder.css("min-height",0)},stop:function(e,o){t.$apply(function(){n.editor.isDragging=!1,n.setIsDropTarget(!1)})},over:function(t,l){l.sender&&l.sender[0].isToolbox&&(l.sender[0].dropTargetTimeout&&(e.cancel(l.sender[0].dropTargetTimeout),l.sender[0].dropTargetTimeout=null),e(function(){if("Row"==n.type){var e=n.editor.dropTargetElement;e&&"Row"==e.type&&e.rollbackAddColumn()}n.setIsDropTarget(!1)}),l.sender[0].dropTargetTimeout=e(function(){if("Row"==n.type){var e=l.item.sortable.model,t=Math.floor(12/(n.children.length+1));e.width=t,e.offset=0,n.beginAddColumn(t);var a=_.max(_(o.find("> .layout-children > .layout-column:not(.ui-sortable-placeholder)")).map(function(e){return $(e).height()}));for(i=1;i<=12;i++)l.placeholder.removeClass("col-xs-"+i);l.placeholder.addClass("col-xs-"+e.width),a>0?(l.placeholder.height(a),l.placeholder.css("min-height",0)):(l.placeholder.height(0),l.placeholder.css("min-height",""))}n.setIsDropTarget(!0)},150))},receive:function(o,l){l.sender&&l.sender[0].isToolbox&&t.$apply(function(){var o=l.item.sortable.model;o&&("Row"==n.type&&n.commitAddColumn(),o.setEditor(n.editor),o.setParent(n),o.hasEditor&&t.$root.editElement(o).done(function(t){t.cancel||(o.data=t.element.data,o.applyElementEditorModel(t.elementEditorModel),o.setHtml&&o.setHtml(t.element.html)),e(function(){t.cancel?o.delete():o.setIsFocused(),n.setIsDropTarget(!1)})})),e(function(){n.setIsDropTarget(!1),o&&o.setIsFocused(),t.$root.addElement(o).done(function(){})})})}},t.click=function(e,t){e.editor.isDragging||e.setIsFocused(),t.stopPropagation()},t.getClasses=function(e){var t=["layout-element"];return e.children&&(t.push("layout-container"),e.getIsSealed()&&t.push("layout-container-sealed")),t.push("layout-"+e.type.toLowerCase()),e.dropTargetClass&&t.push(e.dropTargetClass),"Row"==e.type&&(t.push("row"),e.canAddColumn()||t.push("layout-row-full")),"Column"==e.type&&(t.push("col-xs-"+e.width),t.push("col-xs-offset-"+e.offset)),"Content"==e.type&&t.push("layout-content-"+e.contentTypeClass),e.getIsActive()&&t.push("layout-element-active"),e.getIsFocused()&&t.push("layout-element-focused"),e.getIsSelected()&&t.push("layout-element-selected"),e.getIsDropTarget()&&t.push("layout-element-droptarget"),e.isTemplated&&t.push("layout-element-templated"),t}}}}]),angular.module("LayoutEditor").directive("orcLayoutEditor",["environment",function(environment){return{restrict:"E",scope:{},controller:["$scope","$element","$attrs","$compile","clipboard",function($scope,$element,$attrs,$compile,clipboard){if(!$attrs.model)throw new Error("The 'model' attribute must evaluate to a LayoutEditor.Editor object.");$scope.element=eval($attrs.model),$scope.click=function(e,t){e.editor.isDragging||e.setIsFocused(),t.stopPropagation()},$scope.getClasses=function(e){var t=["layout-element","layout-container","layout-canvas"];return e.getIsActive()&&t.push("layout-element-active"),e.getIsFocused()&&t.push("layout-element-focused"),e.getIsSelected()&&t.push("layout-element-selected"),e.getIsDropTarget()&&t.push("layout-element-droptarget"),e.isTemplated&&t.push("layout-element-templated"),t};var layoutDesignerHost=$(".layout-designer").data("layout-designer-host");$scope.$root.layoutDesignerHost=layoutDesignerHost,layoutDesignerHost.element.on("replacecanvas",function(e,t){var o=$scope.element,n={data:t.canvas.data,htmlId:t.canvas.htmlId,htmlClass:t.canvas.htmlClass,htmlStyle:t.canvas.htmlStyle,isTemplated:t.canvas.isTemplated,children:t.canvas.children};layoutDesignerHost.editor=window.layoutEditor=new LayoutEditor.Editor(o.config,n);var l="",a=$compile(l)($scope);$(".layout-editor-holder").html(a)}),$scope.$root.editElement=function(e){var t=$scope.$root.layoutDesignerHost;return t.editElement(e)},$scope.$root.addElement=function(e){var t=$scope.$root.layoutDesignerHost;return t.addElement(e)},$(document).on("cut copy paste",function(e){if(clipboard.wasInvoked())e.originalEvent.clipboardData.setData("text/plain",clipboard.getData("text/plain")),e.originalEvent.clipboardData.setData("text/json",clipboard.getData("text/json")),e.preventDefault();else{var t=$scope.element.focusedElement;t&&($scope.$apply(function(){switch(e.type){case"copy":t.copy(e.originalEvent.clipboardData);break;case"cut":t.cut(e.originalEvent.clipboardData);break;case"paste":t.paste(e.originalEvent.clipboardData),$.event.trigger({type:"layouteditor:edited"})}}),window.setTimeout(function(){$scope.$apply(function(){$scope.element.focusedElement&&$scope.element.focusedElement.setIsFocused()})},100),e.preventDefault())}clipboard.disable()})}],templateUrl:environment.templateUrl("Editor"),replace:!0,link:function(e,t){t.find(".layout-toolbar-container").click(function(e){e.stopPropagation()}),$(window).click(function(t){e.$apply(function(){e.element.activeElement=null,e.element.focusedElement=null})})}}}]),angular.module("LayoutEditor").directive("orcLayoutCanvas",["scopeConfigurator","environment",function(e,t){return{restrict:"E",scope:{element:"="},controller:["$scope","$element","$attrs",function(t,o,n){e.configureForElement(t,o),e.configureForContainer(t,o),t.sortableOptions.axis="y"}],templateUrl:t.templateUrl("Canvas"),replace:!0}}]),angular.module("LayoutEditor").directive("orcLayoutChild",["$compile",function(e){return{restrict:"E",scope:{element:"="},link:function(t,o){var n="",l=e(n)(t);$(o).replaceWith(l)}}}]),angular.module("LayoutEditor").directive("orcLayoutColumn",["$compile","scopeConfigurator","environment",function(e,t,o){return{restrict:"E",scope:{element:"="},controller:["$scope","$element",function(e,o){t.configureForElement(e,o),t.configureForContainer(e,o),e.sortableOptions.axis="y"}],templateUrl:o.templateUrl("Column"),replace:!0,link:function(e,t,o){t.find(".layout-column-resize-bar").draggable({axis:"x",helper:"clone",revert:!0,start:function(t,o){e.$apply(function(){e.element.editor.isResizing=!0})},drag:function(o,n){var l=t.parent(),a=l.width()/e.element.width,r=!o.ctrlKey;if($(o.target).hasClass("layout-column-resize-bar-left")){var i=n.offset.left-l.offset().left;i<-a&&e.element.canExpandLeft(r)?e.$apply(function(){e.element.expandLeft(r)}):i>a&&e.element.canContractLeft(r)&&e.$apply(function(){e.element.contractLeft(r)})}else if($(o.target).hasClass("layout-column-resize-bar-right")){var i=n.offset.left-l.width()-l.offset().left;i>a&&e.element.canExpandRight(r)?e.$apply(function(){e.element.expandRight(r)}):i<-a&&e.element.canContractRight(r)&&e.$apply(function(){e.element.contractRight(r)})}},stop:function(t,o){e.$apply(function(){e.element.editor.isResizing=!1})}})}}}]),angular.module("LayoutEditor").directive("orcLayoutContent",["$sce","scopeConfigurator","environment",function(e,t,o){return{restrict:"E",scope:{element:"="},controller:["$scope","$element",function(o,n){t.configureForElement(o,n),o.element.setHtml=function(t){o.element.html=t,o.element.htmlUnsafe=e.trustAsHtml(t)},o.element.setHtml(o.element.html)}],templateUrl:o.templateUrl("Content"),replace:!0}}]),angular.module("LayoutEditor").directive("orcLayoutGrid",["$compile","scopeConfigurator","environment",function(e,t,o){return{restrict:"E",scope:{element:"="},controller:["$scope","$element",function(e,o){t.configureForElement(e,o),t.configureForContainer(e,o),e.sortableOptions.axis="y"}],templateUrl:o.templateUrl("Grid"),replace:!0}}]),angular.module("LayoutEditor").directive("orcLayoutRow",["$compile","scopeConfigurator","environment",function(e,t,o){return{restrict:"E",scope:{element:"="},controller:["$scope","$element",function(e,o){t.configureForElement(e,o),t.configureForContainer(e,o),e.sortableOptions.axis="x",e.sortableOptions["ui-floating"]=!0}],templateUrl:o.templateUrl("Row"),replace:!0}}]),angular.module("LayoutEditor").directive("orcLayoutPopup",[function(){return{restrict:"A",link:function(e,t,o){var n=$(t),l=n.closest(".layout-popup-trigger"),a=n.closest(".layout-element");l.click(function(){n.toggle(),n.is(":visible")&&(n.position({my:o.orcLayoutPopupMy||"left top",at:o.orcLayoutPopupAt||"left bottom+4px",of:l}),n.find("input").first().focus())}),n.click(function(e){e.stopPropagation()}),a.click(function(e){n.hide()}),n.keydown(function(e){e.ctrlKey||e.shiftKey||e.altKey||27!=e.which||n.hide(),e.stopPropagation()}),n.on("cut copy paste",function(e){e.stopPropagation()})}}}]),angular.module("LayoutEditor").directive("orcLayoutToolbox",["$compile","environment",function(e,t){return{restrict:"E",controller:["$scope","$element",function(e,t){e.resetElements=function(){e.gridElements=[LayoutEditor.Grid.from({toolboxIcon:"",toolboxLabel:"Grid",toolboxDescription:"Empty grid.",children:[]})],e.rowElements=[LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (1 column)",toolboxDescription:"Row with 1 column.",children:LayoutEditor.Column.times(1)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (2 columns)",toolboxDescription:"Row with 2 columns.",children:LayoutEditor.Column.times(2)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (3 columns)",toolboxDescription:"Row with 3 columns.",children:LayoutEditor.Column.times(3)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (4 columns)",toolboxDescription:"Row with 4 columns.",children:LayoutEditor.Column.times(4)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (6 columns)",toolboxDescription:"Row with 6 columns.",children:LayoutEditor.Column.times(6)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (12 columns)",toolboxDescription:"Row with 12 columns.",children:LayoutEditor.Column.times(12)}),LayoutEditor.Row.from({toolboxIcon:"",toolboxLabel:"Row (empty)",toolboxDescription:"Empty row.",children:[]})],e.columnElements=[LayoutEditor.Column.from({toolboxIcon:"",toolboxLabel:"Column",toolboxDescription:"Empty column.",width:1,offset:0,children:[]})],e.canvasElements=[LayoutEditor.Canvas.from({toolboxIcon:"",toolboxLabel:"Canvas",toolboxDescription:"Empty canvas.",children:[]})],e.contentElementCategories=_(e.element.config.categories).map(function(e){return{name:e.name,elements:_(e.contentTypes).map(function(e){var t=e.type,o=LayoutEditor.factories[t]||LayoutEditor.factories.Content,n={isTemplated:!1,contentType:e.id,contentTypeLabel:e.label,contentTypeClass:e.typeClass,data:null,hasEditor:e.hasEditor,html:e.html},l=o(n);return l.toolboxIcon=e.icon||"",l.toolboxLabel=e.label,l.toolboxDescription=e.description,l})}})},e.resetElements(),e.getSortableOptions=function(o){var n,l,a=t.closest(".layout-editor").attr("id"),r=!1;switch(o){case"Grid":n=[".layout-canvas",".layout-column",".layout-common-holder"],l="layout-element layout-container layout-grid ui-sortable-placeholder";break;case"Row":n=[".layout-grid"],l="layout-element layout-container layout-row row ui-sortable-placeholder";break;case"Column":n=[".layout-row:not(.layout-row-full)"],l="layout-element layout-container layout-column ui-sortable-placeholder",r=!0;break;case"Content":n=[".layout-canvas",".layout-column",".layout-common-holder"],l="layout-element layout-content ui-sortable-placeholder";break;case"Canvas":n=[".layout-canvas",".layout-column",".layout-common-holder"],l="layout-element layout-container layout-grid ui-sortable-placeholder"}return{cursor:"move",connectWith:_(n).map(function(e){return"#"+a+" "+e+":not(.layout-container-sealed) > .layout-element-wrapper > .layout-children"}).join(", "),placeholder:l,"ui-floating":r,helper:"clone",appendTo:"body",create:function(e,t){e.target.isToolbox=!0},start:function(t,o){e.$apply(function(){e.element.isDragging=!0})},stop:function(t,o){e.$apply(function(){e.element.isDragging=!1,e.resetElements()})},over:function(t,o){e.$apply(function(){e.element.canvas.setIsDropTarget(!1)})}}};var o="layoutToolboxCategory_Layout_IsCollapsed";e.layoutIsCollapsed="true"===$.cookie(o),e.toggleLayoutIsCollapsed=function(t){e.layoutIsCollapsed=!e.layoutIsCollapsed,$.cookie(o,e.layoutIsCollapsed,{expires:365}),t.preventDefault(),t.stopPropagation()}}],templateUrl:t.templateUrl("Toolbox"),replace:!0}}]),angular.module("LayoutEditor").directive("orcLayoutToolboxGroup",["$compile","environment",function(e,t){return{restrict:"E",scope:{category:"="},controller:["$scope","$element",function(e,t){var o="layoutToolboxCategory_"+e.category.name+"_IsCollapsed";e.isCollapsed="true"===$.cookie(o),e.toggleIsCollapsed=function(t){e.isCollapsed=!e.isCollapsed,$.cookie(o,e.isCollapsed,{expires:365}),t.preventDefault(),t.stopPropagation()}}],templateUrl:t.templateUrl("ToolboxGroup"),replace:!0}}]); diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/Models.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/Models.js index 7cdc6ad5e23..fef5ef5035c 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/Models.js +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/Models.js @@ -342,12 +342,18 @@ var LayoutEditor; return; var index = _(this.children).indexOf(child); this.children.move(index, index - 1); + $.event.trigger({ + type: "layouteditor:edited" + }); }; this.moveChildDown = function (child) { if (!this.canMoveChildDown(child)) return; var index = _(this.children).indexOf(child); this.children.move(index, index + 1); + $.event.trigger({ + type: "layouteditor:edited" + }); }; this.canMoveChildUp = function (child) { var index = _(this.children).indexOf(child); @@ -836,4 +842,4 @@ var LayoutEditor; }; })(LayoutEditor || (LayoutEditor = {})); -//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L01vZGVscy9IZWxwZXJzLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTW9kZWxzL0VkaXRvci5qcyIsIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L01vZGVscy9SZWN5Y2xlQmluLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTW9kZWxzL0VsZW1lbnQuanMiLCJPcmNoYXJkLldlYi9Nb2R1bGVzL09yY2hhcmQuTGF5b3V0cy9Bc3NldHMvSmF2YVNjcmlwdC9Nb2RlbHMvQ29udGFpbmVyLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTW9kZWxzL0NhbnZhcy5qcyIsIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L01vZGVscy9HcmlkLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTW9kZWxzL1Jvdy5qcyIsIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L01vZGVscy9Db2x1bW4uanMiLCJPcmNoYXJkLldlYi9Nb2R1bGVzL09yY2hhcmQuTGF5b3V0cy9Bc3NldHMvSmF2YVNjcmlwdC9Nb2RlbHMvQ29udGVudC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLElBQUksWUFBWSxDQUFDO0FBQ2pCLENBQUMsVUFBVSxZQUFZO0lBRW5CLEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBSSxHQUFHLFVBQVUsSUFBSSxFQUFFLEVBQUU7UUFDckMsSUFBSSxDQUFD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Q2pCLEtBQUssQ0FBQyxXQUFXLEVBQ2pCLEtBQUssQ0FBQyxnQkFBZ0IsRUFDdEIsS0FBSyxDQUFDLGdCQUFnQixFQUN0QixLQUFLLENBQUMsSUFBSSxFQUNWLEtBQUssQ0FBQyxTQUFTLEVBQ2YsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRWhCLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDbEIsQ0FBQyxDQUFDO0FBRU4sQ0FBQyxDQUFDLENBQUMsWUFBWSxJQUFJLENBQUMsWUFBWSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMiLCJmaWxlIjoiTW9kZWxzLmpzIiwic291cmNlc0NvbnRlbnQiOlsidmFyIExheW91dEVkaXRvcjtcclxuKGZ1bmN0aW9uIChMYXlvdXRFZGl0b3IpIHtcclxuXHJcbiAgICBBcnJheS5wcm90b3R5cGUubW92ZSA9IGZ1bmN0aW9uIChmcm9tLCB0bykge1xyXG4gICAgICAgIHRoaXMuc3BsaWNlKHRvLCAwLCB0aGlzLnNwbGljZShmcm9tLCAxKVswXSk7XHJcbiAgICB9O1xyXG5cclxuICAgIExheW91dEVkaXRvci5jaGlsZHJlbkZyb20gPSBmdW5jdGlvbih2YWx1ZXMpIHtcclxuICAgICAgICByZXR1cm4gXyh2YWx1ZXMpLm1hcChmdW5jdGlvbih2YWx1ZSkge1xyXG4gICAgICAgICAgICByZXR1cm4gTGF5b3V0RWRpdG9yLmVsZW1lbnRGcm9tKHZhbHVlKTtcclxuICAgICAgICB9KTtcclxuICAgIH07XHJcblxyXG4gICAgdmFyIHJlZ2lzdGVyRmFjdG9yeSA9IExheW91dEVkaXRvci5yZWdpc3RlckZhY3RvcnkgPSBmdW5jdGlvbih0eXBlLCBmYWN0b3J5KSB7XHJcbiAgICAgICAgdmFyIGZhY3RvcmllcyA9IExheW91dEVkaXRvci5mYWN0b3JpZXMgPSBMYXlvdXRFZGl0b3IuZmFjdG9yaWVzIHx8IHt9O1xyXG4gICAgICAgIGZhY3Rvcmllc1t0eXBlXSA9IGZhY3Rvcnk7XHJcbiAgICB9O1xyXG5cclxuICAgIHJlZ2lzdGVyRmFjdG9yeShcIkNhbnZhc1wiLCBmdW5jdGlvbiAodmFsdWUpIHsgcmV0dXJuIExheW91dEVkaXRvci5DYW52YXMuZnJvbSh2YWx1ZSk7IH0pO1xyXG4gICAgcmVnaXN0ZXJGYWN0b3J5KFwiR3JpZFwiLCBmdW5jdGlvbih2YWx1ZSkgeyByZXR1cm4gTGF5b3V0RWRpdG9yLkdyaWQuZnJvbSh2YWx1ZSk7IH0pO1xyXG4gICAgcmVnaXN0ZXJGYWN0b3J5KFwiUm93XCIsIGZ1bmN0aW9uKHZhbHVlKSB7IHJldHVybiBMYXlvdXRFZGl0b3IuUm93LmZyb20odmFsdWUpOyB9KTtcclxuICAgIHJlZ2lzdGVyRmFjdG9yeShcIkNvbHVtblwiLCBmdW5jdGlvbih2YWx1ZSkgeyByZXR1cm4gTGF5b3V0RWRpdG9yLkNvbHVtbi5mcm9tKHZhbHVlKTsgfSk7XHJcbiAgICByZWdpc3RlckZhY3RvcnkoXCJDb250ZW50XCIsIGZ1bmN0aW9uKHZhbHVlKSB7IHJldHVybiBMYXlvdXRFZGl0b3IuQ29udGVudC5mcm9tKHZhbHVlKTsgfSk7XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLmVsZW1lbnRGcm9tID0gZnVuY3Rpb24gKHZhbHVlKSB7XHJcbiAgICAgICAgdmFyIGZhY3RvcnkgPSBMYXlvdXRFZGl0b3IuZmFjdG9yaWVzW3ZhbHVlLnR5cGVdO1xyXG5cclxuICAgICAgICBpZiAoIWZhY3RvcnkpXHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk5vIGVsZW1lbnQgd2l0aCB0eXBlIFxcXCJcIiArIHZhbHVlLnR5cGUgKyBcIlxcXCIgd2FzIGZvdW5kLlwiKTtcclxuXHJcbiAgICAgICAgdmFyIGVsZW1lbnQgPSBmYWN0b3J5KHZhbHVlKTtcclxuICAgICAgICByZXR1cm4gZWxlbWVudDtcclxuICAgIH07XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLnNldE1vZGVsID0gZnVuY3Rpb24gKGVsZW1lbnRTZWxlY3RvciwgbW9kZWwpIHtcclxuICAgICAgICAkKGVsZW1lbnRTZWxlY3Rvcikuc2NvcGUoKS5lbGVtZW50ID0gbW9kZWw7XHJcbiAgICB9O1xyXG5cclxuICAgIExheW91dEVkaXRvci5nZXRNb2RlbCA9IGZ1bmN0aW9uIChlbGVtZW50U2VsZWN0b3IpIHtcclxuICAgICAgICByZXR1cm4gJChlbGVtZW50U2VsZWN0b3IpLnNjb3BlKCkuZWxlbWVudDtcclxuICAgIH07XHJcblxyXG59KShMYXlvdXRFZGl0b3IgfHwgKExheW91dEVkaXRvciA9IHt9KSk7IiwidmFyIExheW91dEVkaXRvcjtcclxuKGZ1bmN0aW9uIChMYXlvdXRFZGl0b3IpIHtcclxuXHJcbiAgICBMYXlvdXRFZGl0b3IuRWRpdG9yID0gZnVuY3Rpb24gKGNvbmZpZywgY2FudmFzRGF0YSkge1xyXG4gICAgICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xyXG4gICAgICAgIHRoaXMuY2FudmFzID0gTGF5b3V0RWRpdG9yLkNhbnZhcy5mcm9tKGNhbnZhc0RhdGEpO1xyXG4gICAgICAgIHRoaXMuaW5pdGlhbFN0YXRlID0gSlNPTi5zdHJpbmdpZnkodGhpcy5jYW52YXMudG9PYmplY3QoKSk7XHJcbiAgICAgICAgdGhpcy5hY3RpdmVFbGVtZW50ID0gbnVsbDtcclxuICAgICAgICB0aGlzLmZvY3VzZWRFbGVtZW50ID0gbnVsbDtcclxuICAgICAgICB0aGlzLmRyb3BUYXJnZXRFbGVtZW50ID0gbnVsbDtcclxuICAgICAgICB0aGlzLmlzRHJhZ2dpbmcgPSBmYWxzZTtcclxuICAgICAgICB0aGlzLmlzUmVzaXppbmcgPSBmYWxzZTtcclxuICAgICAgICB0aGlzLnJlY3ljbGVCaW4gPSBuZXcgTGF5b3V0RWRpdG9yLlJlY3ljbGVCaW4oKTtcclxuXHJcbiAgICAgICAgdGhpcy5yZXNldFRvb2xib3hFbGVtZW50cyA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgdGhpcy50b29sYm94RWxlbWVudHMgPSBbXHJcbiAgICAgICAgICAgICAgICBMYXlvdXRFZGl0b3IuUm93LmZyb20oe1xyXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBbXVxyXG4gICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgXTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmlzRGlydHkgPSBmdW5jdGlvbigpIHtcclxuICAgICAgICAgICAgdmFyIGN1cnJlbnRTdGF0ZSA9IEpTT04uc3RyaW5naWZ5KHRoaXMuY2FudmFzLnRvT2JqZWN0KCkpO1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5pbml0aWFsU3RhdGUgIT0gY3VycmVudFN0YXRlO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMucmVzZXRUb29sYm94RWxlbWVudHMoKTtcclxuICAgICAgICB0aGlzLmNhbnZhcy5zZXRFZGl0b3IodGhpcyk7XHJcbiAgICB9O1xyXG5cclxufSkoTGF5b3V0RWRpdG9yIHx8IChMYXlvdXRFZGl0b3IgPSB7fSkpO1xyXG4iLCJ2YXIgTGF5b3V0RWRpdG9yO1xyXG4oZnVuY3Rpb24gKExheW91dEVkaXRvcikge1xyXG5cclxuICAgIExheW91dEVkaXRvci5SZWN5Y2xlQmluID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIHRoaXMuZWxlbWVudHMgPSBbXTtcclxuXHJcbiAgICAgICAgdGhpcy5hZGQgPSBmdW5jdGlvbihlbGVtZW50KSB7XHJcbiAgICAgICAgICAgIHRoaXMuZWxlbWVudHMucHVzaChlbGVtZW50KTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLnRvT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0ge1xyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJSZWN5Y2xlQmluXCIsXHJcbiAgICAgICAgICAgICAgICBjaGlsZHJlbjogW11cclxuICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5lbGVtZW50cy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICAgICAgdmFyIGVsZW1lbnQgPSB0aGlzLmVsZW1lbnRzW2ldO1xyXG4gICAgICAgICAgICAgICAgdmFyIGR0byA9IGVsZW1lbnQudG9PYmplY3QoKTtcclxuICAgICAgICAgICAgICAgIHJlc3VsdC5jaGlsZHJlbi5wdXNoKGR0byk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICAgICAgfTtcclxuICAgIH07XHJcblxyXG59KShMYXlvdXRFZGl0b3IgfHwgKExheW91dEVkaXRvciA9IHt9KSk7XHJcbiIsInZhciBMYXlvdXRFZGl0b3I7XHJcbihmdW5jdGlvbiAoTGF5b3V0RWRpdG9yKSB7XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLkVsZW1lbnQgPSBmdW5jdGlvbiAodHlwZSwgZGF0YSwgaHRtbElkLCBodG1sQ2xhc3MsIGh0bWxTdHlsZSwgaXNUZW1wbGF0ZWQsIHJ1bGUpIHtcclxuICAgICAgICBpZiAoIXR5cGUpXHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlBhcmFtZXRlciAndHlwZScgaXMgcmVxdWlyZWQuXCIpO1xyXG5cclxuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XHJcbiAgICAgICAgdGhpcy50eXBlID0gdHlwZTtcclxuICAgICAgICB0aGlzLmRhdGEgPSBkYXRhO1xyXG4gICAgICAgIHRoaXMuaHRtbElkID0gaHRtbElkO1xyXG4gICAgICAgIHRoaXMuaHRtbENsYXNzID0gaHRtbENsYXNzO1xyXG4gICAgICAgIHRoaXMuaHRtbFN0eWxlID0gaHRtbFN0eWxlO1xyXG4gICAgICAgIHRoaXMuaXNUZW1wbGF0ZWQgPSBpc1RlbXBsYXRlZDtcclxuICAgICAgICB0aGlzLnJ1bGUgPSBydWxlO1xyXG5cclxuICAgICAgICB0aGlzLnRlbXBsYXRlU3R5bGVzID0ge307XHJcbiAgICAgICAgdGhpcy5lZGl0b3IgPSBudWxsO1xyXG4gICAgICAgIHRoaXMucGFyZW50ID0gbnVsbDtcclxuICAgICAgICB0aGlzLnNldElzRm9jdXNlZEV2ZW50SGFuZGxlcnMgPSBbXTtcclxuXHJcbiAgICAgICAgdGhpcy5zZXRFZGl0b3IgPSBmdW5jdGlvbiAoZWRpdG9yKSB7XHJcbiAgICAgICAgICAgIHRoaXMuZWRpdG9yID0gZWRpdG9yO1xyXG4gICAgICAgICAgICBpZiAoISF0aGlzLmNoaWxkcmVuICYmIF8uaXNBcnJheSh0aGlzLmNoaWxkcmVuKSkge1xyXG4gICAgICAgICAgICAgICAgXyh0aGlzLmNoaWxkcmVuKS5lYWNoKGZ1bmN0aW9uIChjaGlsZCkge1xyXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkLnNldEVkaXRvcihlZGl0b3IpO1xyXG4gICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLnNldFBhcmVudCA9IGZ1bmN0aW9uKHBhcmVudEVsZW1lbnQpIHtcclxuICAgICAgICAgICAgdGhpcy5wYXJlbnQgPSBwYXJlbnRFbGVtZW50O1xyXG4gICAgICAgICAgICB0aGlzLnBhcmVudC5vbkNoaWxkQWRkZWQodGhpcyk7XHJcblxyXG4gICAgICAgICAgICB2YXIgY3VycmVudEFuY2VzdG9yID0gcGFyZW50RWxlbWVudDtcclxuICAgICAgICAgICAgd2hpbGUgKCEhY3VycmVudEFuY2VzdG9yKSB7XHJcbiAgICAgICAgICAgICAgICBjdXJyZW50QW5jZXN0b3Iub25EZXNjZW5kYW50QWRkZWQodGhpcywgcGFyZW50RWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICBjdXJyZW50QW5jZXN0b3IgPSBjdXJyZW50QW5jZXN0b3IucGFyZW50O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5zZXRJc1RlbXBsYXRlZCA9IGZ1bmN0aW9uICh2YWx1ZSkge1xyXG4gICAgICAgICAgICB0aGlzLmlzVGVtcGxhdGVkID0gdmFsdWU7XHJcbiAgICAgICAgICAgIGlmICghIXRoaXMuY2hpbGRyZW4gJiYgXy5pc0FycmF5KHRoaXMuY2hpbGRyZW4pKSB7XHJcbiAgICAgICAgICAgICAgICBfKHRoaXMuY2hpbGRyZW4pLmVhY2goZnVuY3Rpb24gKGNoaWxkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgY2hpbGQuc2V0SXNUZW1wbGF0ZWQodmFsdWUpO1xyXG4gICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmFwcGx5RWxlbWVudEVkaXRvck1vZGVsID0gZnVuY3Rpb24oKSB7IC8qIFZpcnR1YWwgKi8gfTtcclxuXHJcbiAgICAgICAgdGhpcy5nZXRJc0FjdGl2ZSA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKCF0aGlzLmVkaXRvcilcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZWRpdG9yLmFjdGl2ZUVsZW1lbnQgPT09IHRoaXMgJiYgIXRoaXMuZ2V0SXNGb2N1c2VkKCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5zZXRJc0FjdGl2ZSA9IGZ1bmN0aW9uICh2YWx1ZSkge1xyXG4gICAgICAgICAgICBpZiAoIXRoaXMuZWRpdG9yKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICBpZiAodGhpcy5lZGl0b3IuaXNEcmFnZ2luZyB8fCB0aGlzLmVkaXRvci5pc1Jlc2l6aW5nKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG5cclxuICAgICAgICAgICAgaWYgKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgdGhpcy5lZGl0b3IuYWN0aXZlRWxlbWVudCA9IHRoaXM7XHJcbiAgICAgICAgICAgIGVsc2VcclxuICAgICAgICAgICAgICAgIHRoaXMuZWRpdG9yLmFjdGl2ZUVsZW1lbnQgPSB0aGlzLnBhcmVudDtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmdldElzRm9jdXNlZCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKCF0aGlzLmVkaXRvcilcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZWRpdG9yLmZvY3VzZWRFbGVtZW50ID09PSB0aGlzO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuc2V0SXNGb2N1c2VkID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAoIXRoaXMuZWRpdG9yKVxyXG4gICAgICAgICAgICBcdHJldHVybjtcclxuICAgICAgICAgICAgaWYgKCF0aGlzLmNoaWxkcmVuICYmIHRoaXMuaXNUZW1wbGF0ZWQpXHJcbiAgICAgICAgICAgIFx0cmV0dXJuO1xyXG4gICAgICAgICAgICBpZiAodGhpcy5lZGl0b3IuaXNEcmFnZ2luZyB8fCB0aGlzLmVkaXRvci5pc1Jlc2l6aW5nKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG5cclxuICAgICAgICAgICAgdGhpcy5lZGl0b3IuZm9jdXNlZEVsZW1lbnQgPSB0aGlzO1xyXG4gICAgICAgICAgICBfKHRoaXMuc2V0SXNGb2N1c2VkRXZlbnRIYW5kbGVycykuZWFjaChmdW5jdGlvbiAoaXRlbSkge1xyXG4gICAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgICAgICBpdGVtKCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBjYXRjaCAoZXgpIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBJZ25vcmUuXHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuZ2V0SXNTZWxlY3RlZCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKHRoaXMuZ2V0SXNGb2N1c2VkKCkpXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuXHJcbiAgICAgICAgICAgIGlmICghIXRoaXMuY2hpbGRyZW4gJiYgXy5pc0FycmF5KHRoaXMuY2hpbGRyZW4pKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gXyh0aGlzLmNoaWxkcmVuKS5hbnkoZnVuY3Rpb24oY2hpbGQpIHtcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gY2hpbGQuZ2V0SXNTZWxlY3RlZCgpO1xyXG4gICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmdldElzRHJvcFRhcmdldCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKCF0aGlzLmVkaXRvcilcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZWRpdG9yLmRyb3BUYXJnZXRFbGVtZW50ID09PSB0aGlzO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhpcy5zZXRJc0Ryb3BUYXJnZXQgPSBmdW5jdGlvbiAodmFsdWUpIHtcclxuICAgICAgICAgICAgaWYgKCF0aGlzLmVkaXRvcilcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgaWYgKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgdGhpcy5lZGl0b3IuZHJvcFRhcmdldEVsZW1lbnQgPSB0aGlzO1xyXG4gICAgICAgICAgICBlbHNlXHJcbiAgICAgICAgICAgICAgICB0aGlzLmVkaXRvci5kcm9wVGFyZ2V0RWxlbWVudCA9IG51bGw7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jYW5EZWxldGUgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmlzVGVtcGxhdGVkIHx8ICF0aGlzLnBhcmVudClcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5kZWxldGUgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5jYW5EZWxldGUoKSlcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgdGhpcy5wYXJlbnQuZGVsZXRlQ2hpbGQodGhpcyk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jYW5Nb3ZlVXAgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmlzVGVtcGxhdGVkIHx8ICF0aGlzLnBhcmVudClcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMucGFyZW50LmNhbk1vdmVDaGlsZFVwKHRoaXMpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMubW92ZVVwID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAoIXRoaXMuY2FuTW92ZVVwKCkpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIHRoaXMucGFyZW50Lm1vdmVDaGlsZFVwKHRoaXMpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuY2FuTW92ZURvd24gPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmlzVGVtcGxhdGVkIHx8ICF0aGlzLnBhcmVudClcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMucGFyZW50LmNhbk1vdmVDaGlsZERvd24odGhpcyk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5tb3ZlRG93biA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKCF0aGlzLmNhbk1vdmVEb3duKCkpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIHRoaXMucGFyZW50Lm1vdmVDaGlsZERvd24odGhpcyk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5lbGVtZW50VG9PYmplY3QgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICB0eXBlOiB0aGlzLnR5cGUsXHJcbiAgICAgICAgICAgICAgICBkYXRhOiB0aGlzLmRhdGEsXHJcbiAgICAgICAgICAgICAgICBodG1sSWQ6IHRoaXMuaHRtbElkLFxyXG4gICAgICAgICAgICAgICAgaHRtbENsYXNzOiB0aGlzLmh0bWxDbGFzcyxcclxuICAgICAgICAgICAgICAgIGh0bWxTdHlsZTogdGhpcy5odG1sU3R5bGUsXHJcbiAgICAgICAgICAgICAgICBpc1RlbXBsYXRlZDogdGhpcy5pc1RlbXBsYXRlZCxcclxuICAgICAgICAgICAgICAgIHJ1bGU6IHRoaXMucnVsZSxcclxuICAgICAgICAgICAgICAgIGNvbnRlbnRUeXBlOiB0aGlzLmNvbnRlbnRUeXBlLFxyXG4gICAgICAgICAgICAgICAgaGFzRWRpdG9yOiB0aGlzLmhhc0VkaXRvclxyXG4gICAgICAgICAgICB9O1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuZ2V0RWRpdG9yT2JqZWN0ID0gZnVuY3Rpb24oKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB7fTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLnRvT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICByZXR1cm4gc2VsZi5lbGVtZW50VG9PYmplY3QoKTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNvcHkgPSBmdW5jdGlvbiAoY2xpcGJvYXJkRGF0YSkge1xyXG4gICAgICAgICAgICB2YXIgdGV4dCA9IHRoaXMuZ2V0SW5uZXJUZXh0KCk7XHJcbiAgICAgICAgICAgIGNsaXBib2FyZERhdGEuc2V0RGF0YShcInRleHQvcGxhaW5cIiwgdGV4dCk7XHJcblxyXG4gICAgICAgICAgICB2YXIgZGF0YSA9IHRoaXMudG9PYmplY3QoKTtcclxuICAgICAgICAgICAgdmFyIGpzb24gPSBKU09OLnN0cmluZ2lmeShkYXRhLCBudWxsLCBcIlxcdFwiKTtcclxuICAgICAgICAgICAgY2xpcGJvYXJkRGF0YS5zZXREYXRhKFwidGV4dC9qc29uXCIsIGpzb24pO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuY3V0ID0gZnVuY3Rpb24gKGNsaXBib2FyZERhdGEpIHtcclxuICAgICAgICAgICAgaWYgKHRoaXMuY2FuRGVsZXRlKCkpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMuY29weShjbGlwYm9hcmREYXRhKTtcclxuICAgICAgICAgICAgICAgIHRoaXMuZGVsZXRlKCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLnBhc3RlID0gZnVuY3Rpb24gKGNsaXBib2FyZERhdGEpIHtcclxuICAgICAgICAgICAgaWYgKCEhdGhpcy5wYXJlbnQpXHJcbiAgICAgICAgICAgICAgICB0aGlzLnBhcmVudC5wYXN0ZShjbGlwYm9hcmREYXRhKTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmdldFRlbXBsYXRlU3R5bGVzID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICB2YXIgc3R5bGVzID0gdGhpcy50ZW1wbGF0ZVN0eWxlcyB8fCB7fTtcclxuICAgICAgICAgICAgdmFyIGNzcyA9IFwiXCI7XHJcblxyXG4gICAgICAgICAgICBmb3IgKHZhciBwcm9wZXJ0eSBpbiBzdHlsZXMpIHtcclxuICAgICAgICAgICAgICAgIGNzcyArPSBwcm9wZXJ0eSArIFwiOlwiICsgc3R5bGVzW3Byb3BlcnR5XSArIFwiO1wiO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICByZXR1cm4gY3NzO1xyXG4gICAgICAgIH1cclxuICAgIH07XHJcblxyXG59KShMYXlvdXRFZGl0b3IgfHwgKExheW91dEVkaXRvciA9IHt9KSk7IiwidmFyIExheW91dEVkaXRvcjtcclxuKGZ1bmN0aW9uIChMYXlvdXRFZGl0b3IpIHtcclxuXHJcbiAgICBMYXlvdXRFZGl0b3IuQ29udGFpbmVyID0gZnVuY3Rpb24gKGFsbG93ZWRDaGlsZFR5cGVzLCBjaGlsZHJlbikge1xyXG5cclxuICAgICAgICB0aGlzLmFsbG93ZWRDaGlsZFR5cGVzID0gYWxsb3dlZENoaWxkVHlwZXM7XHJcbiAgICAgICAgdGhpcy5jaGlsZHJlbiA9IGNoaWxkcmVuO1xyXG4gICAgICAgIHRoaXMuaXNDb250YWluZXIgPSB0cnVlO1xyXG4gICAgICAgIHRoaXMuY29udGFpbmVyVGVtcGxhdGVTdHlsZXMgPSB7fTtcclxuXHJcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xyXG5cclxuICAgICAgICB0aGlzLm9uQ2hpbGRBZGRlZCA9IGZ1bmN0aW9uIChlbGVtZW50KSB7IC8qIFZpcnR1YWwgKi8gfTtcclxuICAgICAgICB0aGlzLm9uRGVzY2VuZGFudEFkZGVkID0gZnVuY3Rpb24gKGVsZW1lbnQsIHBhcmVudEVsZW1lbnQpIHsgLyogVmlydHVhbCAqLyB9O1xyXG5cclxuICAgICAgICB0aGlzLnNldENoaWxkcmVuID0gZnVuY3Rpb24gKGNoaWxkcmVuKSB7XHJcbiAgICAgICAgICAgIHRoaXMuY2hpbGRyZW4gPSBjaGlsZHJlbjtcclxuICAgICAgICAgICAgXyh0aGlzLmNoaWxkcmVuKS5lYWNoKGZ1bmN0aW9uIChjaGlsZCkge1xyXG4gICAgICAgICAgICAgICAgY2hpbGQuc2V0UGFyZW50KHNlbGYpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLnNldENoaWxkcmVuKGNoaWxkcmVuKTtcclxuXHJcbiAgICAgICAgdGhpcy5nZXRJc1NlYWxlZCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgcmV0dXJuIF8odGhpcy5jaGlsZHJlbikuYW55KGZ1bmN0aW9uIChjaGlsZCkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNoaWxkLmlzVGVtcGxhdGVkO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB2YXIgX2Jhc2VTZXRJc0ZvY3VzZWQgPSB0aGlzLnNldElzRm9jdXNlZDtcclxuICAgICAgICB0aGlzLnNldElzRm9jdXNlZCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKHRoaXMuZ2V0SXNTZWFsZWQoKSlcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgX2Jhc2VTZXRJc0ZvY3VzZWQuY2FsbCh0aGlzKTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmFkZENoaWxkID0gZnVuY3Rpb24gKGNoaWxkKSB7XHJcbiAgICAgICAgICAgIGlmICghXyh0aGlzLmNoaWxkcmVuKS5jb250YWlucyhjaGlsZCkgJiYgKF8odGhpcy5hbGxvd2VkQ2hpbGRUeXBlcykuY29udGFpbnMoY2hpbGQudHlwZSkgfHwgY2hpbGQuaXNDb250YWluYWJsZSkpXHJcbiAgICAgICAgICAgICAgICB0aGlzLmNoaWxkcmVuLnB1c2goY2hpbGQpO1xyXG4gICAgICAgICAgICBjaGlsZC5zZXRFZGl0b3IodGhpcy5lZGl0b3IpO1xyXG4gICAgICAgICAgICBjaGlsZC5zZXRJc1RlbXBsYXRlZChmYWxzZSk7XHJcbiAgICAgICAgICAgIGNoaWxkLnNldFBhcmVudCh0aGlzKTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmRlbGV0ZUNoaWxkID0gZnVuY3Rpb24gKGNoaWxkKSB7XHJcbiAgICAgICAgICAgIHZhciBpbmRleCA9IF8odGhpcy5jaGlsZHJlbikuaW5kZXhPZihjaGlsZCk7XHJcbiAgICAgICAgICAgIGlmIChpbmRleCA+PSAwKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmNoaWxkcmVuLnNwbGljZShpbmRleCwgMSk7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmVkaXRvci5yZWN5Y2xlQmluLmFkZChjaGlsZCk7XHJcbiAgICAgICAgICAgICAgICBpZiAoY2hpbGQuZ2V0SXNBY3RpdmUoKSlcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLmVkaXRvci5hY3RpdmVFbGVtZW50ID0gbnVsbDtcclxuICAgICAgICAgICAgICAgIGlmIChjaGlsZC5nZXRJc0ZvY3VzZWQoKSkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIElmIHRoZSBkZWxldGVkIGNoaWxkIHdhcyBmb2N1c2VkLCB0cnkgdG8gc2V0IG5ldyBmb2N1cyB0byB0aGUgbW9zdCBhcHByb3ByaWF0ZSBzaWJsaW5nIG9yIHBhcmVudC5cclxuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5jaGlsZHJlbi5sZW5ndGggPiBpbmRleClcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jaGlsZHJlbltpbmRleF0uc2V0SXNGb2N1c2VkKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoaW5kZXggPiAwKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNoaWxkcmVuW2luZGV4IC0gMV0uc2V0SXNGb2N1c2VkKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNldElzRm9jdXNlZCgpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5tb3ZlRm9jdXNQcmV2Q2hpbGQgPSBmdW5jdGlvbiAoY2hpbGQpIHtcclxuICAgICAgICAgICAgaWYgKHRoaXMuY2hpbGRyZW4ubGVuZ3RoIDwgMilcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgdmFyIGluZGV4ID0gXyh0aGlzLmNoaWxkcmVuKS5pbmRleE9mKGNoaWxkKTtcclxuICAgICAgICAgICAgaWYgKGluZGV4ID4gMClcclxuICAgICAgICAgICAgICAgIHRoaXMuY2hpbGRyZW5baW5kZXggLSAxXS5zZXRJc0ZvY3VzZWQoKTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLm1vdmVGb2N1c05leHRDaGlsZCA9IGZ1bmN0aW9uIChjaGlsZCkge1xyXG4gICAgICAgICAgICBpZiAodGhpcy5jaGlsZHJlbi5sZW5ndGggPCAyKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB2YXIgaW5kZXggPSBfKHRoaXMuY2hpbGRyZW4pLmluZGV4T2YoY2hpbGQpO1xyXG4gICAgICAgICAgICBpZiAoaW5kZXggPCB0aGlzLmNoaWxkcmVuLmxlbmd0aCAtIDEpXHJcbiAgICAgICAgICAgICAgICB0aGlzLmNoaWxkcmVuW2luZGV4ICsgMV0uc2V0SXNGb2N1c2VkKCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5pbnNlcnRDaGlsZCA9IGZ1bmN0aW9uIChjaGlsZCwgYWZ0ZXJDaGlsZCkge1xyXG4gICAgICAgICAgICBpZiAoIV8odGhpcy5jaGlsZHJlbikuY29udGFpbnMoY2hpbGQpKSB7XHJcbiAgICAgICAgICAgICAgICB2YXIgaW5kZXggPSBNYXRoLm1heChfKHRoaXMuY2hpbGRyZW4pLmluZGV4T2YoYWZ0ZXJDaGlsZCksIDApO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5jaGlsZHJlbi5zcGxpY2UoaW5kZXggKyAxLCAwLCBjaGlsZCk7XHJcbiAgICAgICAgICAgICAgICBjaGlsZC5zZXRFZGl0b3IodGhpcy5lZGl0b3IpO1xyXG4gICAgICAgICAgICAgICAgY2hpbGQucGFyZW50ID0gdGhpcztcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMubW92ZUNoaWxkVXAgPSBmdW5jdGlvbiAoY2hpbGQpIHtcclxuICAgICAgICAgICAgaWYgKCF0aGlzLmNhbk1vdmVDaGlsZFVwKGNoaWxkKSlcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgdmFyIGluZGV4ID0gXyh0aGlzLmNoaWxkcmVuKS5pbmRleE9mKGNoaWxkKTtcclxuICAgICAgICAgICAgdGhpcy5jaGlsZHJlbi5tb3ZlKGluZGV4LCBpbmRleCAtIDEpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMubW92ZUNoaWxkRG93biA9IGZ1bmN0aW9uIChjaGlsZCkge1xyXG4gICAgICAgICAgICBpZiAoIXRoaXMuY2FuTW92ZUNoaWxkRG93bihjaGlsZCkpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIHZhciBpbmRleCA9IF8odGhpcy5jaGlsZHJlbikuaW5kZXhPZihjaGlsZCk7XHJcbiAgICAgICAgICAgIHRoaXMuY2hpbGRyZW4ubW92ZShpbmRleCwgaW5kZXggKyAxKTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNhbk1vdmVDaGlsZFVwID0gZnVuY3Rpb24gKGNoaWxkKSB7XHJcbiAgICAgICAgICAgIHZhciBpbmRleCA9IF8odGhpcy5jaGlsZHJlbikuaW5kZXhPZihjaGlsZCk7XHJcbiAgICAgICAgICAgIHJldHVybiBpbmRleCA+IDA7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jYW5Nb3ZlQ2hpbGREb3duID0gZnVuY3Rpb24gKGNoaWxkKSB7XHJcbiAgICAgICAgICAgIHZhciBpbmRleCA9IF8odGhpcy5jaGlsZHJlbikuaW5kZXhPZihjaGlsZCk7XHJcbiAgICAgICAgICAgIHJldHVybiBpbmRleCA8IHRoaXMuY2hpbGRyZW4ubGVuZ3RoIC0gMTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNoaWxkcmVuVG9PYmplY3QgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBfKHRoaXMuY2hpbGRyZW4pLm1hcChmdW5jdGlvbiAoY2hpbGQpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybiBjaGlsZC50b09iamVjdCgpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmdldElubmVyVGV4dCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgcmV0dXJuIF8odGhpcy5jaGlsZHJlbikucmVkdWNlKGZ1bmN0aW9uIChtZW1vLCBjaGlsZCkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lbW8gKyBcIlxcblwiICsgY2hpbGQuZ2V0SW5uZXJUZXh0KCk7XHJcbiAgICAgICAgICAgIH0sIFwiXCIpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhpcy5wYXN0ZSA9IGZ1bmN0aW9uIChjbGlwYm9hcmREYXRhKSB7XHJcbiAgICAgICAgICAgIHZhciBqc29uID0gY2xpcGJvYXJkRGF0YS5nZXREYXRhKFwidGV4dC9qc29uXCIpO1xyXG4gICAgICAgICAgICBpZiAoISFqc29uKSB7XHJcbiAgICAgICAgICAgICAgICB2YXIgZGF0YSA9IEpTT04ucGFyc2UoanNvbik7XHJcbiAgICAgICAgICAgICAgICB2YXIgY2hpbGQgPSBMYXlvdXRFZGl0b3IuZWxlbWVudEZyb20oZGF0YSk7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnBhc3RlQ2hpbGQoY2hpbGQpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5wYXN0ZUNoaWxkID0gZnVuY3Rpb24gKGNoaWxkKSB7XHJcbiAgICAgICAgICAgIGlmIChfKHRoaXMuYWxsb3dlZENoaWxkVHlwZXMpLmNvbnRhaW5zKGNoaWxkLnR5cGUpIHx8IGNoaWxkLmlzQ29udGFpbmFibGUpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMuYWRkQ2hpbGQoY2hpbGQpO1xyXG4gICAgICAgICAgICAgICAgY2hpbGQuc2V0SXNGb2N1c2VkKCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgZWxzZSBpZiAoISF0aGlzLnBhcmVudClcclxuICAgICAgICAgICAgICAgIHRoaXMucGFyZW50LnBhc3RlQ2hpbGQoY2hpbGQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhpcy5nZXRDb250YWluZXJUZW1wbGF0ZVN0eWxlcyA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgdmFyIHN0eWxlcyA9IHRoaXMuY29udGFpbmVyVGVtcGxhdGVTdHlsZXMgfHwge307XHJcbiAgICAgICAgICAgIHZhciBjc3MgPSBcIlwiO1xyXG5cclxuICAgICAgICAgICAgZm9yICh2YXIgcHJvcGVydHkgaW4gc3R5bGVzKSB7XHJcbiAgICAgICAgICAgICAgICBjc3MgKz0gcHJvcGVydHkgKyBcIjpcIiArIHN0eWxlc1twcm9wZXJ0eV0gKyBcIjtcIjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgcmV0dXJuIGNzcztcclxuICAgICAgICB9XHJcbiAgICB9O1xyXG5cclxufSkoTGF5b3V0RWRpdG9yIHx8IChMYXlvdXRFZGl0b3IgPSB7fSkpOyIsInZhciBMYXlvdXRFZGl0b3I7XHJcbihmdW5jdGlvbiAoTGF5b3V0RWRpdG9yKSB7XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLkNhbnZhcyA9IGZ1bmN0aW9uIChkYXRhLCBodG1sSWQsIGh0bWxDbGFzcywgaHRtbFN0eWxlLCBpc1RlbXBsYXRlZCwgcnVsZSwgY2hpbGRyZW4pIHtcclxuICAgICAgICBMYXlvdXRFZGl0b3IuRWxlbWVudC5jYWxsKHRoaXMsIFwiQ2FudmFzXCIsIGRhdGEsIGh0bWxJZCwgaHRtbENsYXNzLCBodG1sU3R5bGUsIGlzVGVtcGxhdGVkLCBydWxlKTtcclxuICAgICAgICBMYXlvdXRFZGl0b3IuQ29udGFpbmVyLmNhbGwodGhpcywgW1wiQ2FudmFzXCIsIFwiR3JpZFwiLCBcIkNvbnRlbnRcIl0sIGNoaWxkcmVuKTtcclxuXHJcbiAgICAgICAgdGhpcy5pc0NvbnRhaW5hYmxlID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgdGhpcy50b09iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHRoaXMuZWxlbWVudFRvT2JqZWN0KCk7XHJcbiAgICAgICAgICAgIHJlc3VsdC5jaGlsZHJlbiA9IHRoaXMuY2hpbGRyZW5Ub09iamVjdCgpO1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgICAgIH07XHJcbiAgICB9O1xyXG5cclxuICAgIExheW91dEVkaXRvci5DYW52YXMuZnJvbSA9IGZ1bmN0aW9uICh2YWx1ZSkge1xyXG4gICAgICAgIHZhciByZXN1bHQgPSBuZXcgTGF5b3V0RWRpdG9yLkNhbnZhcyhcclxuICAgICAgICAgICAgdmFsdWUuZGF0YSxcclxuICAgICAgICAgICAgdmFsdWUuaHRtbElkLFxyXG4gICAgICAgICAgICB2YWx1ZS5odG1sQ2xhc3MsXHJcbiAgICAgICAgICAgIHZhbHVlLmh0bWxTdHlsZSxcclxuICAgICAgICAgICAgdmFsdWUuaXNUZW1wbGF0ZWQsXHJcbiAgICAgICAgICAgIHZhbHVlLnJ1bGUsXHJcbiAgICAgICAgICAgIExheW91dEVkaXRvci5jaGlsZHJlbkZyb20odmFsdWUuY2hpbGRyZW4pKTtcclxuXHJcbiAgICAgICAgcmVzdWx0LnRvb2xib3hJY29uID0gdmFsdWUudG9vbGJveEljb247XHJcbiAgICAgICAgcmVzdWx0LnRvb2xib3hMYWJlbCA9IHZhbHVlLnRvb2xib3hMYWJlbDtcclxuICAgICAgICByZXN1bHQudG9vbGJveERlc2NyaXB0aW9uID0gdmFsdWUudG9vbGJveERlc2NyaXB0aW9uO1xyXG5cclxuICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgfTtcclxuXHJcbn0pKExheW91dEVkaXRvciB8fCAoTGF5b3V0RWRpdG9yID0ge30pKTtcclxuIiwidmFyIExheW91dEVkaXRvcjtcclxuKGZ1bmN0aW9uIChMYXlvdXRFZGl0b3IpIHtcclxuXHJcbiAgICBMYXlvdXRFZGl0b3IuR3JpZCA9IGZ1bmN0aW9uIChkYXRhLCBodG1sSWQsIGh0bWxDbGFzcywgaHRtbFN0eWxlLCBpc1RlbXBsYXRlZCwgcnVsZSwgY2hpbGRyZW4pIHtcclxuICAgICAgICBMYXlvdXRFZGl0b3IuRWxlbWVudC5jYWxsKHRoaXMsIFwiR3JpZFwiLCBkYXRhLCBodG1sSWQsIGh0bWxDbGFzcywgaHRtbFN0eWxlLCBpc1RlbXBsYXRlZCwgcnVsZSk7XHJcbiAgICAgICAgTGF5b3V0RWRpdG9yLkNvbnRhaW5lci5jYWxsKHRoaXMsIFtcIlJvd1wiXSwgY2hpbGRyZW4pO1xyXG5cclxuICAgICAgICB0aGlzLnRvT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gdGhpcy5lbGVtZW50VG9PYmplY3QoKTtcclxuICAgICAgICAgICAgcmVzdWx0LmNoaWxkcmVuID0gdGhpcy5jaGlsZHJlblRvT2JqZWN0KCk7XHJcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICAgICAgfTtcclxuICAgIH07XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLkdyaWQuZnJvbSA9IGZ1bmN0aW9uICh2YWx1ZSkge1xyXG4gICAgICAgIHZhciByZXN1bHQgPSBuZXcgTGF5b3V0RWRpdG9yLkdyaWQoXHJcbiAgICAgICAgICAgIHZhbHVlLmRhdGEsXHJcbiAgICAgICAgICAgIHZhbHVlLmh0bWxJZCxcclxuICAgICAgICAgICAgdmFsdWUuaHRtbENsYXNzLFxyXG4gICAgICAgICAgICB2YWx1ZS5odG1sU3R5bGUsXHJcbiAgICAgICAgICAgIHZhbHVlLmlzVGVtcGxhdGVkLFxyXG4gICAgICAgICAgICB2YWx1ZS5ydWxlLFxyXG4gICAgICAgICAgICBMYXlvdXRFZGl0b3IuY2hpbGRyZW5Gcm9tKHZhbHVlLmNoaWxkcmVuKSk7XHJcbiAgICAgICAgcmVzdWx0LnRvb2xib3hJY29uID0gdmFsdWUudG9vbGJveEljb247XHJcbiAgICAgICAgcmVzdWx0LnRvb2xib3hMYWJlbCA9IHZhbHVlLnRvb2xib3hMYWJlbDtcclxuICAgICAgICByZXN1bHQudG9vbGJveERlc2NyaXB0aW9uID0gdmFsdWUudG9vbGJveERlc2NyaXB0aW9uO1xyXG4gICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICB9O1xyXG5cclxufSkoTGF5b3V0RWRpdG9yIHx8IChMYXlvdXRFZGl0b3IgPSB7fSkpOyIsInZhciBMYXlvdXRFZGl0b3I7XHJcbihmdW5jdGlvbiAoTGF5b3V0RWRpdG9yKSB7XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLlJvdyA9IGZ1bmN0aW9uIChkYXRhLCBodG1sSWQsIGh0bWxDbGFzcywgaHRtbFN0eWxlLCBpc1RlbXBsYXRlZCwgcnVsZSwgY2hpbGRyZW4pIHtcclxuICAgICAgICBMYXlvdXRFZGl0b3IuRWxlbWVudC5jYWxsKHRoaXMsIFwiUm93XCIsIGRhdGEsIGh0bWxJZCwgaHRtbENsYXNzLCBodG1sU3R5bGUsIGlzVGVtcGxhdGVkLCBydWxlKTtcclxuICAgICAgICBMYXlvdXRFZGl0b3IuQ29udGFpbmVyLmNhbGwodGhpcywgW1wiQ29sdW1uXCJdLCBjaGlsZHJlbik7XHJcblxyXG4gICAgICAgIHZhciBfc2VsZiA9IHRoaXM7XHJcblxyXG4gICAgICAgIGZ1bmN0aW9uIF9nZXRUb3RhbENvbHVtbnNXaWR0aCgpIHtcclxuICAgICAgICAgICAgcmV0dXJuIF8oX3NlbGYuY2hpbGRyZW4pLnJlZHVjZShmdW5jdGlvbiAobWVtbywgY2hpbGQpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybiBtZW1vICsgY2hpbGQub2Zmc2V0ICsgY2hpbGQud2lkdGg7XHJcbiAgICAgICAgICAgIH0sIDApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSW1wbGVtZW50cyBhIHNpbXBsZSBhbGdvcml0aG0gdG8gZGlzdHJpYnV0ZSBzcGFjZSAoZWl0aGVyIHBvc2l0aXZlIG9yIG5lZ2F0aXZlKVxyXG4gICAgICAgIC8vIGJldHdlZW4gdGhlIGNoaWxkIGNvbHVtbnMgb2YgdGhlIHJvdy4gTmVnYXRpdmUgc3BhY2UgaXMgZGlzdHJpYnV0ZWQgd2hlbiBtYWtpbmdcclxuICAgICAgICAvLyByb29tIGZvciBhIG5ldyBjb2x1bW4gKGUuYy4gY2xpcGJvYXJkIHBhc3RlIG9yIGRyb3BwaW5nIGZyb20gdGhlIHRvb2xib3gpIHdoaWxlXHJcbiAgICAgICAgLy8gcG9zaXRpdmUgc3BhY2UgaXMgZGlzdHJpYnV0ZWQgd2hlbiBmaWxsaW5nIHRoZSBncmFwIG9mIGEgcmVtb3ZlZCBjb2x1bW4uXHJcbiAgICAgICAgZnVuY3Rpb24gX2Rpc3RyaWJ1dGVTcGFjZShzcGFjZSkge1xyXG4gICAgICAgICAgICBpZiAoc3BhY2UgPT0gMClcclxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgICAgXHJcbiAgICAgICAgICAgIHZhciB1bmRpc3RyaWJ1dGVkU3BhY2UgPSBzcGFjZTtcclxuXHJcbiAgICAgICAgICAgIGlmICh1bmRpc3RyaWJ1dGVkU3BhY2UgPCAwKSB7XHJcbiAgICAgICAgICAgICAgICB2YXIgdmFjYW50U3BhY2UgPSAxMiAtIF9nZXRUb3RhbENvbHVtbnNXaWR0aCgpO1xyXG4gICAgICAgICAgICAgICAgdW5kaXN0cmlidXRlZFNwYWNlICs9IHZhY2FudFNwYWNlO1xyXG4gICAgICAgICAgICAgICAgaWYgKHVuZGlzdHJpYnV0ZWRTcGFjZSA+IDApXHJcbiAgICAgICAgICAgICAgICAgICAgdW5kaXN0cmlidXRlZFNwYWNlID0gMDtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gSWYgc3BhY2UgaXMgbmVnYXRpdmUsIHRyeSB0byBkZWNyZWFzZSBvZmZzZXRzIGZpcnN0LlxyXG4gICAgICAgICAgICB3aGlsZSAodW5kaXN0cmlidXRlZFNwYWNlIDwgMCAmJiBfKF9zZWxmLmNoaWxkcmVuKS5hbnkoZnVuY3Rpb24gKGNvbHVtbikgeyByZXR1cm4gY29sdW1uLm9mZnNldCA+IDA7IH0pKSB7IC8vIFdoaWxlIHRoZXJlIGlzIHN0aWxsIG9mZnNldCBsZWZ0IHRvIHJlbW92ZS5cclxuICAgICAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBfc2VsZi5jaGlsZHJlbi5sZW5ndGggJiYgdW5kaXN0cmlidXRlZFNwYWNlIDwgMDsgaSsrKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdmFyIGNvbHVtbiA9IF9zZWxmLmNoaWxkcmVuW2ldO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChjb2x1bW4ub2Zmc2V0ID4gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW4ub2Zmc2V0LS07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHVuZGlzdHJpYnV0ZWRTcGFjZSsrO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgZnVuY3Rpb24gaGFzV2lkdGgoY29sdW1uKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAodW5kaXN0cmlidXRlZFNwYWNlID4gMClcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gY29sdW1uLndpZHRoIDwgMTI7XHJcbiAgICAgICAgICAgICAgICBlbHNlIGlmICh1bmRpc3RyaWJ1dGVkU3BhY2UgPCAwKVxyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBjb2x1bW4ud2lkdGggPiAxO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBUcnkgdG8gZGlzdHJpYnV0ZSByZW1haW5pbmcgc3BhY2UgKGNvdWxkIGJlIG5lZ2F0aXZlIG9yIHBvc2l0aXZlKSB1c2luZyB3aWR0aHMuXHJcbiAgICAgICAgICAgIHdoaWxlICh1bmRpc3RyaWJ1dGVkU3BhY2UgIT0gMCkge1xyXG4gICAgICAgICAgICAgICAgLy8gQW55IG1vcmUgY29sdW1uIHdpZHRoIGF2YWlsYWJsZSBmb3IgZGlzdHJpYnV0aW9uP1xyXG4gICAgICAgICAgICAgICAgaWYgKCFfKF9zZWxmLmNoaWxkcmVuKS5hbnkoaGFzV2lkdGgpKVxyXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IF9zZWxmLmNoaWxkcmVuLmxlbmd0aCAmJiB1bmRpc3RyaWJ1dGVkU3BhY2UgIT0gMDsgaSsrKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdmFyIGNvbHVtbiA9IF9zZWxmLmNoaWxkcmVuW2kgJSBfc2VsZi5jaGlsZHJlbi5sZW5ndGhdO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChoYXNXaWR0aChjb2x1bW4pKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBkZWx0YSA9IHVuZGlzdHJpYnV0ZWRTcGFjZSAvIE1hdGguYWJzKHVuZGlzdHJpYnV0ZWRTcGFjZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbi53aWR0aCArPSBkZWx0YTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdW5kaXN0cmlidXRlZFNwYWNlIC09IGRlbHRhO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0gICAgICAgICAgICAgICAgXHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHJldHVybiB1bmRpc3RyaWJ1dGVkU3BhY2UgPT0gMDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHZhciBfaXNBZGRpbmdDb2x1bW4gPSBmYWxzZTtcclxuXHJcbiAgICAgICAgdGhpcy5jYW5BZGRDb2x1bW4gPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNoaWxkcmVuLmxlbmd0aCA8IDEyO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuYmVnaW5BZGRDb2x1bW4gPSBmdW5jdGlvbiAobmV3Q29sdW1uV2lkdGgpIHtcclxuICAgICAgICAgICAgaWYgKCEhX2lzQWRkaW5nQ29sdW1uKVxyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ29sdW1uIGFkZCBvcGVyYXRpb24gaXMgYWxyZWFkeSBpbiBwcm9ncmVzcy5cIilcclxuICAgICAgICAgICAgXyh0aGlzLmNoaWxkcmVuKS5lYWNoKGZ1bmN0aW9uIChjb2x1bW4pIHtcclxuICAgICAgICAgICAgICAgIGNvbHVtbi5iZWdpbkNoYW5nZSgpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgaWYgKF9kaXN0cmlidXRlU3BhY2UoLW5ld0NvbHVtbldpZHRoKSkge1xyXG4gICAgICAgICAgICAgICAgX2lzQWRkaW5nQ29sdW1uID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIF8odGhpcy5jaGlsZHJlbikuZWFjaChmdW5jdGlvbiAoY29sdW1uKSB7XHJcbiAgICAgICAgICAgICAgICBjb2x1bW4ucm9sbGJhY2tDaGFuZ2UoKTtcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNvbW1pdEFkZENvbHVtbiA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKCFfaXNBZGRpbmdDb2x1bW4pXHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJObyBjb2x1bW4gYWRkIG9wZXJhdGlvbiBpbiBwcm9ncmVzcy5cIilcclxuICAgICAgICAgICAgXyh0aGlzLmNoaWxkcmVuKS5lYWNoKGZ1bmN0aW9uIChjb2x1bW4pIHtcclxuICAgICAgICAgICAgICAgIGNvbHVtbi5jb21taXRDaGFuZ2UoKTtcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIF9pc0FkZGluZ0NvbHVtbiA9IGZhbHNlO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMucm9sbGJhY2tBZGRDb2x1bW4gPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICghX2lzQWRkaW5nQ29sdW1uKVxyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gY29sdW1uIGFkZCBvcGVyYXRpb24gaW4gcHJvZ3Jlc3MuXCIpXHJcbiAgICAgICAgICAgIF8odGhpcy5jaGlsZHJlbikuZWFjaChmdW5jdGlvbiAoY29sdW1uKSB7XHJcbiAgICAgICAgICAgICAgICBjb2x1bW4ucm9sbGJhY2tDaGFuZ2UoKTtcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIF9pc0FkZGluZ0NvbHVtbiA9IGZhbHNlO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHZhciBfYmFzZURlbGV0ZUNoaWxkID0gdGhpcy5kZWxldGVDaGlsZDtcclxuICAgICAgICB0aGlzLmRlbGV0ZUNoaWxkID0gZnVuY3Rpb24gKGNvbHVtbikgeyBcclxuICAgICAgICAgICAgdmFyIHdpZHRoID0gY29sdW1uLndpZHRoO1xyXG4gICAgICAgICAgICBfYmFzZURlbGV0ZUNoaWxkLmNhbGwodGhpcywgY29sdW1uKTtcclxuICAgICAgICAgICAgX2Rpc3RyaWJ1dGVTcGFjZSh3aWR0aCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jYW5Db250cmFjdENvbHVtblJpZ2h0ID0gZnVuY3Rpb24gKGNvbHVtbiwgY29ubmVjdEFkamFjZW50KSB7XHJcbiAgICAgICAgICAgIHZhciBpbmRleCA9IF8odGhpcy5jaGlsZHJlbikuaW5kZXhPZihjb2x1bW4pO1xyXG4gICAgICAgICAgICBpZiAoaW5kZXggPj0gMClcclxuICAgICAgICAgICAgICAgIHJldHVybiBjb2x1bW4ud2lkdGggPiAxO1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jb250cmFjdENvbHVtblJpZ2h0ID0gZnVuY3Rpb24gKGNvbHVtbiwgY29ubmVjdEFkamFjZW50KSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5jYW5Db250cmFjdENvbHVtblJpZ2h0KGNvbHVtbiwgY29ubmVjdEFkamFjZW50KSlcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuXHJcbiAgICAgICAgICAgIHZhciBpbmRleCA9IF8odGhpcy5jaGlsZHJlbikuaW5kZXhPZihjb2x1bW4pO1xyXG4gICAgICAgICAgICBpZiAoaW5kZXggPj0gMCkge1xyXG4gICAgICAgICAgICAgICAgaWYgKGNvbHVtbi53aWR0aCA+IDEpIHtcclxuICAgICAgICAgICAgICAgICAgICBjb2x1bW4ud2lkdGgtLTtcclxuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5jaGlsZHJlbi5sZW5ndGggPiBpbmRleCArIDEpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIG5leHRDb2x1bW4gPSB0aGlzLmNoaWxkcmVuW2luZGV4ICsgMV07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjb25uZWN0QWRqYWNlbnQgJiYgbmV4dENvbHVtbi5vZmZzZXQgPT0gMClcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5leHRDb2x1bW4ud2lkdGgrKztcclxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV4dENvbHVtbi5vZmZzZXQrKztcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNhbkV4cGFuZENvbHVtblJpZ2h0ID0gZnVuY3Rpb24gKGNvbHVtbiwgY29ubmVjdEFkamFjZW50KSB7XHJcbiAgICAgICAgICAgIHZhciBpbmRleCA9IF8odGhpcy5jaGlsZHJlbikuaW5kZXhPZihjb2x1bW4pO1xyXG4gICAgICAgICAgICBpZiAoaW5kZXggPj0gMCkge1xyXG4gICAgICAgICAgICAgICAgaWYgKGNvbHVtbi53aWR0aCA+PSAxMilcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5jaGlsZHJlbi5sZW5ndGggPiBpbmRleCArIDEpIHtcclxuICAgICAgICAgICAgICAgICAgICB2YXIgbmV4dENvbHVtbiA9IHRoaXMuY2hpbGRyZW5baW5kZXggKyAxXTtcclxuICAgICAgICAgICAgICAgICAgICBpZiAoY29ubmVjdEFkamFjZW50ICYmIG5leHRDb2x1bW4ub2Zmc2V0ID09IDApXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXh0Q29sdW1uLndpZHRoID4gMTtcclxuICAgICAgICAgICAgICAgICAgICBlbHNlXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXh0Q29sdW1uLm9mZnNldCA+IDA7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gX2dldFRvdGFsQ29sdW1uc1dpZHRoKCkgPCAxMjtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5leHBhbmRDb2x1bW5SaWdodCA9IGZ1bmN0aW9uIChjb2x1bW4sIGNvbm5lY3RBZGphY2VudCkge1xyXG4gICAgICAgICAgICBpZiAoIXRoaXMuY2FuRXhwYW5kQ29sdW1uUmlnaHQoY29sdW1uLCBjb25uZWN0QWRqYWNlbnQpKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG5cclxuICAgICAgICAgICAgdmFyIGluZGV4ID0gXyh0aGlzLmNoaWxkcmVuKS5pbmRleE9mKGNvbHVtbik7XHJcbiAgICAgICAgICAgIGlmIChpbmRleCA+PSAwKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5jaGlsZHJlbi5sZW5ndGggPiBpbmRleCArIDEpIHtcclxuICAgICAgICAgICAgICAgICAgICB2YXIgbmV4dENvbHVtbiA9IHRoaXMuY2hpbGRyZW5baW5kZXggKyAxXTtcclxuICAgICAgICAgICAgICAgICAgICBpZiAoY29ubmVjdEFkamFjZW50ICYmIG5leHRDb2x1bW4ub2Zmc2V0ID09IDApXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG5leHRDb2x1bW4ud2lkdGgtLTtcclxuICAgICAgICAgICAgICAgICAgICBlbHNlXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG5leHRDb2x1bW4ub2Zmc2V0LS07XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBjb2x1bW4ud2lkdGgrKztcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuY2FuRXhwYW5kQ29sdW1uTGVmdCA9IGZ1bmN0aW9uIChjb2x1bW4sIGNvbm5lY3RBZGphY2VudCkge1xyXG4gICAgICAgICAgICB2YXIgaW5kZXggPSBfKHRoaXMuY2hpbGRyZW4pLmluZGV4T2YoY29sdW1uKTtcclxuICAgICAgICAgICAgaWYgKGluZGV4ID49IDApIHtcclxuICAgICAgICAgICAgICAgIGlmIChjb2x1bW4ud2lkdGggPj0gMTIpXHJcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgICAgICAgICAgaWYgKGluZGV4ID4gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciBwcmV2Q29sdW1uID0gdGhpcy5jaGlsZHJlbltpbmRleCAtIDFdO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChjb25uZWN0QWRqYWNlbnQgJiYgY29sdW1uLm9mZnNldCA9PSAwKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcHJldkNvbHVtbi53aWR0aCA+IDE7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gY29sdW1uLm9mZnNldCA+IDA7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuZXhwYW5kQ29sdW1uTGVmdCA9IGZ1bmN0aW9uIChjb2x1bW4sIGNvbm5lY3RBZGphY2VudCkge1xyXG4gICAgICAgICAgICBpZiAoIXRoaXMuY2FuRXhwYW5kQ29sdW1uTGVmdChjb2x1bW4sIGNvbm5lY3RBZGphY2VudCkpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcblxyXG4gICAgICAgICAgICB2YXIgaW5kZXggPSBfKHRoaXMuY2hpbGRyZW4pLmluZGV4T2YoY29sdW1uKTtcclxuICAgICAgICAgICAgaWYgKGluZGV4ID49IDApIHtcclxuICAgICAgICAgICAgICAgIGlmIChpbmRleCA+IDApIHtcclxuICAgICAgICAgICAgICAgICAgICB2YXIgcHJldkNvbHVtbiA9IHRoaXMuY2hpbGRyZW5baW5kZXggLSAxXTtcclxuICAgICAgICAgICAgICAgICAgICBpZiAoY29ubmVjdEFkamFjZW50ICYmIGNvbHVtbi5vZmZzZXQgPT0gMClcclxuICAgICAgICAgICAgICAgICAgICAgICAgcHJldkNvbHVtbi53aWR0aC0tO1xyXG4gICAgICAgICAgICAgICAgICAgIGVsc2VcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uLm9mZnNldC0tO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICAgICAgICAgIGNvbHVtbi5vZmZzZXQtLTtcclxuICAgICAgICAgICAgICAgIGNvbHVtbi53aWR0aCsrO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jYW5Db250cmFjdENvbHVtbkxlZnQgPSBmdW5jdGlvbiAoY29sdW1uLCBjb25uZWN0QWRqYWNlbnQpIHtcclxuICAgICAgICAgICAgdmFyIGluZGV4ID0gXyh0aGlzLmNoaWxkcmVuKS5pbmRleE9mKGNvbHVtbik7XHJcbiAgICAgICAgICAgIGlmIChpbmRleCA+PSAwKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNvbHVtbi53aWR0aCA+IDE7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNvbnRyYWN0Q29sdW1uTGVmdCA9IGZ1bmN0aW9uIChjb2x1bW4sIGNvbm5lY3RBZGphY2VudCkge1xyXG4gICAgICAgICAgICBpZiAoIXRoaXMuY2FuQ29udHJhY3RDb2x1bW5MZWZ0KGNvbHVtbiwgY29ubmVjdEFkamFjZW50KSlcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuXHJcbiAgICAgICAgICAgIHZhciBpbmRleCA9IF8odGhpcy5jaGlsZHJlbikuaW5kZXhPZihjb2x1bW4pO1xyXG4gICAgICAgICAgICBpZiAoaW5kZXggPj0gMCkge1xyXG4gICAgICAgICAgICAgICAgaWYgKGluZGV4ID4gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciBwcmV2Q29sdW1uID0gdGhpcy5jaGlsZHJlbltpbmRleCAtIDFdO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChjb25uZWN0QWRqYWNlbnQgJiYgY29sdW1uLm9mZnNldCA9PSAwKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICBwcmV2Q29sdW1uLndpZHRoKys7XHJcbiAgICAgICAgICAgICAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW4ub2Zmc2V0Kys7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBlbHNlXHJcbiAgICAgICAgICAgICAgICAgICAgY29sdW1uLm9mZnNldCsrO1xyXG4gICAgICAgICAgICAgICAgY29sdW1uLndpZHRoLS07XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmV2ZW5Db2x1bW5zID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAodGhpcy5jaGlsZHJlbi5sZW5ndGggPT0gMClcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuXHJcbiAgICAgICAgICAgIHZhciBldmVuV2lkdGggPSBNYXRoLmZsb29yKDEyIC8gdGhpcy5jaGlsZHJlbi5sZW5ndGgpO1xyXG4gICAgICAgICAgICBfKHRoaXMuY2hpbGRyZW4pLmVhY2goZnVuY3Rpb24gKGNvbHVtbikge1xyXG4gICAgICAgICAgICAgICAgY29sdW1uLndpZHRoID0gZXZlbldpZHRoO1xyXG4gICAgICAgICAgICAgICAgY29sdW1uLm9mZnNldCA9IDA7XHJcbiAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgdmFyIHJlc3QgPSAxMiAlIHRoaXMuY2hpbGRyZW4ubGVuZ3RoO1xyXG4gICAgICAgICAgICBpZiAocmVzdCA+IDApXHJcbiAgICAgICAgICAgICAgICBfZGlzdHJpYnV0ZVNwYWNlKHJlc3QpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHZhciBfYmFzZVBhc3RlQ2hpbGQgPSB0aGlzLnBhc3RlQ2hpbGQ7XHJcbiAgICAgICAgdGhpcy5wYXN0ZUNoaWxkID0gZnVuY3Rpb24gKGNoaWxkKSB7XHJcbiAgICAgICAgICAgIGlmIChjaGlsZC50eXBlID09IFwiQ29sdW1uXCIpIHtcclxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmJlZ2luQWRkQ29sdW1uKGNoaWxkLndpZHRoKSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29tbWl0QWRkQ29sdW1uKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgX2Jhc2VQYXN0ZUNoaWxkLmNhbGwodGhpcywgY2hpbGQpXHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgZWxzZSBpZiAoISF0aGlzLnBhcmVudClcclxuICAgICAgICAgICAgICAgIHRoaXMucGFyZW50LnBhc3RlQ2hpbGQoY2hpbGQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhpcy50b09iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHRoaXMuZWxlbWVudFRvT2JqZWN0KCk7XHJcbiAgICAgICAgICAgIHJlc3VsdC5jaGlsZHJlbiA9IHRoaXMuY2hpbGRyZW5Ub09iamVjdCgpO1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgICAgIH07XHJcbiAgICB9O1xyXG5cclxuICAgIExheW91dEVkaXRvci5Sb3cuZnJvbSA9IGZ1bmN0aW9uICh2YWx1ZSkge1xyXG4gICAgICAgIHZhciByZXN1bHQgPSBuZXcgTGF5b3V0RWRpdG9yLlJvdyhcclxuICAgICAgICAgICAgdmFsdWUuZGF0YSxcclxuICAgICAgICAgICAgdmFsdWUuaHRtbElkLFxyXG4gICAgICAgICAgICB2YWx1ZS5odG1sQ2xhc3MsXHJcbiAgICAgICAgICAgIHZhbHVlLmh0bWxTdHlsZSxcclxuICAgICAgICAgICAgdmFsdWUuaXNUZW1wbGF0ZWQsXHJcbiAgICAgICAgICAgIHZhbHVlLnJ1bGUsXHJcbiAgICAgICAgICAgIExheW91dEVkaXRvci5jaGlsZHJlbkZyb20odmFsdWUuY2hpbGRyZW4pKTtcclxuICAgICAgICByZXN1bHQudG9vbGJveEljb24gPSB2YWx1ZS50b29sYm94SWNvbjtcclxuICAgICAgICByZXN1bHQudG9vbGJveExhYmVsID0gdmFsdWUudG9vbGJveExhYmVsO1xyXG4gICAgICAgIHJlc3VsdC50b29sYm94RGVzY3JpcHRpb24gPSB2YWx1ZS50b29sYm94RGVzY3JpcHRpb247XHJcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgIH07XHJcblxyXG59KShMYXlvdXRFZGl0b3IgfHwgKExheW91dEVkaXRvciA9IHt9KSk7IiwidmFyIExheW91dEVkaXRvcjtcclxuKGZ1bmN0aW9uIChMYXlvdXRFZGl0b3IpIHtcclxuICAgIExheW91dEVkaXRvci5Db2x1bW4gPSBmdW5jdGlvbiAoZGF0YSwgaHRtbElkLCBodG1sQ2xhc3MsIGh0bWxTdHlsZSwgaXNUZW1wbGF0ZWQsIHdpZHRoLCBvZmZzZXQsIGNvbGxhcHNpYmxlLCBydWxlLCBjaGlsZHJlbikge1xyXG4gICAgICAgIExheW91dEVkaXRvci5FbGVtZW50LmNhbGwodGhpcywgXCJDb2x1bW5cIiwgZGF0YSwgaHRtbElkLCBodG1sQ2xhc3MsIGh0bWxTdHlsZSwgaXNUZW1wbGF0ZWQsIHJ1bGUpO1xyXG4gICAgICAgIExheW91dEVkaXRvci5Db250YWluZXIuY2FsbCh0aGlzLCBbXCJHcmlkXCIsIFwiQ29udGVudFwiXSwgY2hpbGRyZW4pO1xyXG5cclxuICAgICAgICB0aGlzLndpZHRoID0gd2lkdGg7XHJcbiAgICAgICAgdGhpcy5vZmZzZXQgPSBvZmZzZXQ7XHJcbiAgICAgICAgdGhpcy5jb2xsYXBzaWJsZSA9IGNvbGxhcHNpYmxlO1xyXG5cclxuICAgICAgICB2YXIgX2hhc1BlbmRpbmdDaGFuZ2UgPSBmYWxzZTtcclxuICAgICAgICB2YXIgX29yaWdXaWR0aCA9IDA7XHJcbiAgICAgICAgdmFyIF9vcmlnT2Zmc2V0ID0gMDtcclxuXHJcbiAgICAgICAgdGhpcy5iZWdpbkNoYW5nZSA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKCEhX2hhc1BlbmRpbmdDaGFuZ2UpXHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb2x1bW4gYWxyZWFkeSBoYXMgYSBwZW5kaW5nIGNoYW5nZS5cIik7XHJcbiAgICAgICAgICAgIF9oYXNQZW5kaW5nQ2hhbmdlID0gdHJ1ZTtcclxuICAgICAgICAgICAgX29yaWdXaWR0aCA9IHRoaXMud2lkdGg7XHJcbiAgICAgICAgICAgIF9vcmlnT2Zmc2V0ID0gdGhpcy5vZmZzZXQ7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jb21taXRDaGFuZ2UgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICghX2hhc1BlbmRpbmdDaGFuZ2UpXHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb2x1bW4gaGFzIG5vIHBlbmRpbmcgY2hhbmdlLlwiKTtcclxuICAgICAgICAgICAgX29yaWdXaWR0aCA9IDA7XHJcbiAgICAgICAgICAgIF9vcmlnT2Zmc2V0ID0gMDtcclxuICAgICAgICAgICAgX2hhc1BlbmRpbmdDaGFuZ2UgPSBmYWxzZTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLnJvbGxiYWNrQ2hhbmdlID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAoIV9oYXNQZW5kaW5nQ2hhbmdlKVxyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ29sdW1uIGhhcyBubyBwZW5kaW5nIGNoYW5nZS5cIik7XHJcbiAgICAgICAgICAgIHRoaXMud2lkdGggPSBfb3JpZ1dpZHRoO1xyXG4gICAgICAgICAgICB0aGlzLm9mZnNldCA9IF9vcmlnT2Zmc2V0O1xyXG4gICAgICAgICAgICBfb3JpZ1dpZHRoID0gMDtcclxuICAgICAgICAgICAgX29yaWdPZmZzZXQgPSAwO1xyXG4gICAgICAgICAgICBfaGFzUGVuZGluZ0NoYW5nZSA9IGZhbHNlO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuY2FuU3BsaXQgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmlzVGVtcGxhdGVkKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy53aWR0aCA+IDE7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5zcGxpdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKCF0aGlzLmNhblNwbGl0KCkpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcblxyXG4gICAgICAgICAgICB2YXIgbmV3Q29sdW1uV2lkdGggPSBNYXRoLmZsb29yKHRoaXMud2lkdGggLyAyKTtcclxuICAgICAgICAgICAgdmFyIG5ld0NvbHVtbiA9IExheW91dEVkaXRvci5Db2x1bW4uZnJvbSh7XHJcbiAgICAgICAgICAgICAgICBkYXRhOiBudWxsLFxyXG4gICAgICAgICAgICAgICAgaHRtbElkOiBudWxsLFxyXG4gICAgICAgICAgICAgICAgaHRtbENsYXNzOiBudWxsLFxyXG4gICAgICAgICAgICAgICAgaHRtbFN0eWxlOiBudWxsLFxyXG4gICAgICAgICAgICAgICAgd2lkdGg6IG5ld0NvbHVtbldpZHRoLFxyXG4gICAgICAgICAgICAgICAgb2Zmc2V0OiAwLFxyXG4gICAgICAgICAgICAgICAgY2hpbGRyZW46IFtdXHJcbiAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgdGhpcy53aWR0aCA9IHRoaXMud2lkdGggLSBuZXdDb2x1bW5XaWR0aDtcclxuICAgICAgICAgICAgdGhpcy5wYXJlbnQuaW5zZXJ0Q2hpbGQobmV3Q29sdW1uLCB0aGlzKTtcclxuICAgICAgICAgICAgbmV3Q29sdW1uLnNldElzRm9jdXNlZCgpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuY2FuQ29udHJhY3RSaWdodCA9IGZ1bmN0aW9uIChjb25uZWN0QWRqYWNlbnQpIHtcclxuICAgICAgICAgICAgaWYgKHRoaXMuaXNUZW1wbGF0ZWQpXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcmVudC5jYW5Db250cmFjdENvbHVtblJpZ2h0KHRoaXMsIGNvbm5lY3RBZGphY2VudCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jb250cmFjdFJpZ2h0ID0gZnVuY3Rpb24gKGNvbm5lY3RBZGphY2VudCkge1xyXG4gICAgICAgICAgICBpZiAoIXRoaXMuY2FuQ29udHJhY3RSaWdodChjb25uZWN0QWRqYWNlbnQpKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB0aGlzLnBhcmVudC5jb250cmFjdENvbHVtblJpZ2h0KHRoaXMsIGNvbm5lY3RBZGphY2VudCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jYW5FeHBhbmRSaWdodCA9IGZ1bmN0aW9uIChjb25uZWN0QWRqYWNlbnQpIHtcclxuICAgICAgICAgICAgaWYgKHRoaXMuaXNUZW1wbGF0ZWQpXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcmVudC5jYW5FeHBhbmRDb2x1bW5SaWdodCh0aGlzLCBjb25uZWN0QWRqYWNlbnQpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuZXhwYW5kUmlnaHQgPSBmdW5jdGlvbiAoY29ubmVjdEFkamFjZW50KSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5jYW5FeHBhbmRSaWdodChjb25uZWN0QWRqYWNlbnQpKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB0aGlzLnBhcmVudC5leHBhbmRDb2x1bW5SaWdodCh0aGlzLCBjb25uZWN0QWRqYWNlbnQpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuY2FuRXhwYW5kTGVmdCA9IGZ1bmN0aW9uIChjb25uZWN0QWRqYWNlbnQpIHtcclxuICAgICAgICAgICAgaWYgKHRoaXMuaXNUZW1wbGF0ZWQpXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcmVudC5jYW5FeHBhbmRDb2x1bW5MZWZ0KHRoaXMsIGNvbm5lY3RBZGphY2VudCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5leHBhbmRMZWZ0ID0gZnVuY3Rpb24gKGNvbm5lY3RBZGphY2VudCkge1xyXG4gICAgICAgICAgICBpZiAoIXRoaXMuY2FuRXhwYW5kTGVmdChjb25uZWN0QWRqYWNlbnQpKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB0aGlzLnBhcmVudC5leHBhbmRDb2x1bW5MZWZ0KHRoaXMsIGNvbm5lY3RBZGphY2VudCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jYW5Db250cmFjdExlZnQgPSBmdW5jdGlvbiAoY29ubmVjdEFkamFjZW50KSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmlzVGVtcGxhdGVkKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wYXJlbnQuY2FuQ29udHJhY3RDb2x1bW5MZWZ0KHRoaXMsIGNvbm5lY3RBZGphY2VudCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jb250cmFjdExlZnQgPSBmdW5jdGlvbiAoY29ubmVjdEFkamFjZW50KSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5jYW5Db250cmFjdExlZnQoY29ubmVjdEFkamFjZW50KSlcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgdGhpcy5wYXJlbnQuY29udHJhY3RDb2x1bW5MZWZ0KHRoaXMsIGNvbm5lY3RBZGphY2VudCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy50b09iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHRoaXMuZWxlbWVudFRvT2JqZWN0KCk7XHJcbiAgICAgICAgICAgIHJlc3VsdC53aWR0aCA9IHRoaXMud2lkdGg7XHJcbiAgICAgICAgICAgIHJlc3VsdC5vZmZzZXQgPSB0aGlzLm9mZnNldDtcclxuICAgICAgICAgICAgcmVzdWx0LmNvbGxhcHNpYmxlID0gdGhpcy5jb2xsYXBzaWJsZTtcclxuICAgICAgICAgICAgcmVzdWx0LmNoaWxkcmVuID0gdGhpcy5jaGlsZHJlblRvT2JqZWN0KCk7XHJcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICAgICAgfTtcclxuICAgIH07XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLkNvbHVtbi5mcm9tID0gZnVuY3Rpb24gKHZhbHVlKSB7XHJcbiAgICAgICAgdmFyIHJlc3VsdCA9IG5ldyBMYXlvdXRFZGl0b3IuQ29sdW1uKFxyXG4gICAgICAgICAgICB2YWx1ZS5kYXRhLFxyXG4gICAgICAgICAgICB2YWx1ZS5odG1sSWQsXHJcbiAgICAgICAgICAgIHZhbHVlLmh0bWxDbGFzcyxcclxuICAgICAgICAgICAgdmFsdWUuaHRtbFN0eWxlLFxyXG4gICAgICAgICAgICB2YWx1ZS5pc1RlbXBsYXRlZCxcclxuICAgICAgICAgICAgdmFsdWUud2lkdGgsXHJcbiAgICAgICAgICAgIHZhbHVlLm9mZnNldCxcclxuICAgICAgICAgICAgdmFsdWUuY29sbGFwc2libGUsXHJcbiAgICAgICAgICAgIHZhbHVlLnJ1bGUsXHJcbiAgICAgICAgICAgIExheW91dEVkaXRvci5jaGlsZHJlbkZyb20odmFsdWUuY2hpbGRyZW4pKTtcclxuICAgICAgICByZXN1bHQudG9vbGJveEljb24gPSB2YWx1ZS50b29sYm94SWNvbjtcclxuICAgICAgICByZXN1bHQudG9vbGJveExhYmVsID0gdmFsdWUudG9vbGJveExhYmVsO1xyXG4gICAgICAgIHJlc3VsdC50b29sYm94RGVzY3JpcHRpb24gPSB2YWx1ZS50b29sYm94RGVzY3JpcHRpb247XHJcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgIH07XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLkNvbHVtbi50aW1lcyA9IGZ1bmN0aW9uICh2YWx1ZSkge1xyXG4gICAgICAgIHJldHVybiBfLnRpbWVzKHZhbHVlLCBmdW5jdGlvbiAobikge1xyXG4gICAgICAgICAgICByZXR1cm4gTGF5b3V0RWRpdG9yLkNvbHVtbi5mcm9tKHtcclxuICAgICAgICAgICAgICAgIGRhdGE6IG51bGwsXHJcbiAgICAgICAgICAgICAgICBodG1sSWQ6IG51bGwsXHJcbiAgICAgICAgICAgICAgICBodG1sQ2xhc3M6IG51bGwsXHJcbiAgICAgICAgICAgICAgICBpc1RlbXBsYXRlZDogZmFsc2UsXHJcbiAgICAgICAgICAgICAgICB3aWR0aDogMTIgLyB2YWx1ZSxcclxuICAgICAgICAgICAgICAgIG9mZnNldDogMCxcclxuICAgICAgICAgICAgICAgIGNvbGxhcHNpYmxlOiBudWxsLFxyXG4gICAgICAgICAgICAgICAgY2hpbGRyZW46IFtdXHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfTtcclxufSkoTGF5b3V0RWRpdG9yIHx8IChMYXlvdXRFZGl0b3IgPSB7fSkpOyIsInZhciBMYXlvdXRFZGl0b3I7XHJcbihmdW5jdGlvbiAoTGF5b3V0RWRpdG9yKSB7XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLkNvbnRlbnQgPSBmdW5jdGlvbiAoZGF0YSwgaHRtbElkLCBodG1sQ2xhc3MsIGh0bWxTdHlsZSwgaXNUZW1wbGF0ZWQsIGNvbnRlbnRUeXBlLCBjb250ZW50VHlwZUxhYmVsLCBjb250ZW50VHlwZUNsYXNzLCBodG1sLCBoYXNFZGl0b3IsIHJ1bGUpIHtcclxuICAgICAgICBMYXlvdXRFZGl0b3IuRWxlbWVudC5jYWxsKHRoaXMsIFwiQ29udGVudFwiLCBkYXRhLCBodG1sSWQsIGh0bWxDbGFzcywgaHRtbFN0eWxlLCBpc1RlbXBsYXRlZCwgcnVsZSk7XHJcblxyXG4gICAgICAgIHRoaXMuY29udGVudFR5cGUgPSBjb250ZW50VHlwZTtcclxuICAgICAgICB0aGlzLmNvbnRlbnRUeXBlTGFiZWwgPSBjb250ZW50VHlwZUxhYmVsO1xyXG4gICAgICAgIHRoaXMuY29udGVudFR5cGVDbGFzcyA9IGNvbnRlbnRUeXBlQ2xhc3M7XHJcbiAgICAgICAgdGhpcy5odG1sID0gaHRtbDtcclxuICAgICAgICB0aGlzLmhhc0VkaXRvciA9IGhhc0VkaXRvcjtcclxuXHJcbiAgICAgICAgdGhpcy5nZXRJbm5lclRleHQgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIHJldHVybiAkKCQucGFyc2VIVE1MKFwiPGRpdj5cIiArIHRoaXMuaHRtbCArIFwiPC9kaXY+XCIpKS50ZXh0KCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgLy8gVGhpcyBmdW5jdGlvbiB3aWxsIGJlIG92ZXJ3cml0dGVuIGJ5IHRoZSBDb250ZW50IGRpcmVjdGl2ZS5cclxuICAgICAgICB0aGlzLnNldEh0bWwgPSBmdW5jdGlvbiAoaHRtbCkge1xyXG4gICAgICAgICAgICB0aGlzLmh0bWwgPSBodG1sO1xyXG4gICAgICAgICAgICB0aGlzLmh0bWxVbnNhZmUgPSBodG1sO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdmFyIGJhc2VUb09iamVjdCA9IHRoaXMudG9PYmplY3Q7XHJcbiAgICAgICAgdGhpcy50b09iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IGJhc2VUb09iamVjdCgpO1xyXG4gICAgICAgICAgICByZXN1bHQuY29udGVudFR5cGVMYWJlbCA9IHRoaXMuY29udGVudFR5cGVMYWJlbDtcclxuICAgICAgICAgICAgcmVzdWx0LmNvbnRlbnRUeXBlQ2xhc3MgPSB0aGlzLmNvbnRlbnRUeXBlQ2xhc3M7XHJcbiAgICAgICAgICAgIHJlc3VsdC5odG1sID0gdGhpcy5odG1sO1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuc2V0SHRtbChodG1sKTtcclxuICAgIH07XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLkNvbnRlbnQuZnJvbSA9IGZ1bmN0aW9uICh2YWx1ZSkge1xyXG4gICAgICAgIHZhciByZXN1bHQgPSBuZXcgTGF5b3V0RWRpdG9yLkNvbnRlbnQoXHJcbiAgICAgICAgICAgIHZhbHVlLmRhdGEsXHJcbiAgICAgICAgICAgIHZhbHVlLmh0bWxJZCxcclxuICAgICAgICAgICAgdmFsdWUuaHRtbENsYXNzLFxyXG4gICAgICAgICAgICB2YWx1ZS5odG1sU3R5bGUsXHJcbiAgICAgICAgICAgIHZhbHVlLmlzVGVtcGxhdGVkLFxyXG4gICAgICAgICAgICB2YWx1ZS5jb250ZW50VHlwZSxcclxuICAgICAgICAgICAgdmFsdWUuY29udGVudFR5cGVMYWJlbCxcclxuICAgICAgICAgICAgdmFsdWUuY29udGVudFR5cGVDbGFzcyxcclxuICAgICAgICAgICAgdmFsdWUuaHRtbCxcclxuICAgICAgICAgICAgdmFsdWUuaGFzRWRpdG9yLFxyXG4gICAgICAgICAgICB2YWx1ZS5ydWxlKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgIH07XHJcblxyXG59KShMYXlvdXRFZGl0b3IgfHwgKExheW91dEVkaXRvciA9IHt9KSk7Il19 +//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L01vZGVscy9IZWxwZXJzLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTW9kZWxzL0VkaXRvci5qcyIsIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L01vZGVscy9SZWN5Y2xlQmluLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTW9kZWxzL0VsZW1lbnQuanMiLCJPcmNoYXJkLldlYi9Nb2R1bGVzL09yY2hhcmQuTGF5b3V0cy9Bc3NldHMvSmF2YVNjcmlwdC9Nb2RlbHMvQ29udGFpbmVyLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTW9kZWxzL0NhbnZhcy5qcyIsIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L01vZGVscy9HcmlkLmpzIiwiT3JjaGFyZC5XZWIvTW9kdWxlcy9PcmNoYXJkLkxheW91dHMvQXNzZXRzL0phdmFTY3JpcHQvTW9kZWxzL1Jvdy5qcyIsIk9yY2hhcmQuV2ViL01vZHVsZXMvT3JjaGFyZC5MYXlvdXRzL0Fzc2V0cy9KYXZhU2NyaXB0L01vZGVscy9Db2x1bW4uanMiLCJPcmNoYXJkLldlYi9Nb2R1bGVzL09yY2hhcmQuTGF5b3V0cy9Bc3NldHMvSmF2YVNjcmlwdC9Nb2RlbHMvQ29udGVudC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLElBQUksWUFBWSxDQUFDO0FBQ2pCLENBQUMsVUFBVSxZQUFZO0lBRW5CLEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBSSxHQUFHLFVBQVUsSUFBSSxFQUFFLEVBQUU7UUFDckMsSUFBSSxDQUFD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QUFLO1FBQ3ZDLElBQUksTUFBTSxHQUFHLElBQUksWUFBWSxDQUFDLE9BQU8sQ0FDakMsS0FBSyxDQUFDLElBQUksRUFDVixLQUFLLENBQUMsTUFBTSxFQUNaLEtBQUssQ0FBQyxTQUFTLEVBQ2YsS0FBSyxDQUFDLFNBQVMsRUFDZixLQUFLLENBQUMsV0FBVyxFQUNqQixLQUFLLENBQUMsV0FBVyxFQUNqQixLQUFLLENBQUMsZ0JBQWdCLEVBQ3RCLEtBQUssQ0FBQyxnQkFBZ0IsRUFDdEIsS0FBSyxDQUFDLElBQUksRUFDVixLQUFLLENBQUMsU0FBUyxFQUNmLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUVoQixNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ2xCLENBQUMsQ0FBQztBQUVOLENBQUMsQ0FBQyxDQUFDLFlBQVksSUFBSSxDQUFDLFlBQVksR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDIiwiZmlsZSI6Ik1vZGVscy5qcyIsInNvdXJjZXNDb250ZW50IjpbInZhciBMYXlvdXRFZGl0b3I7XHJcbihmdW5jdGlvbiAoTGF5b3V0RWRpdG9yKSB7XHJcblxyXG4gICAgQXJyYXkucHJvdG90eXBlLm1vdmUgPSBmdW5jdGlvbiAoZnJvbSwgdG8pIHtcclxuICAgICAgICB0aGlzLnNwbGljZSh0bywgMCwgdGhpcy5zcGxpY2UoZnJvbSwgMSlbMF0pO1xyXG4gICAgfTtcclxuXHJcbiAgICBMYXlvdXRFZGl0b3IuY2hpbGRyZW5Gcm9tID0gZnVuY3Rpb24odmFsdWVzKSB7XHJcbiAgICAgICAgcmV0dXJuIF8odmFsdWVzKS5tYXAoZnVuY3Rpb24odmFsdWUpIHtcclxuICAgICAgICAgICAgcmV0dXJuIExheW91dEVkaXRvci5lbGVtZW50RnJvbSh2YWx1ZSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9O1xyXG5cclxuICAgIHZhciByZWdpc3RlckZhY3RvcnkgPSBMYXlvdXRFZGl0b3IucmVnaXN0ZXJGYWN0b3J5ID0gZnVuY3Rpb24odHlwZSwgZmFjdG9yeSkge1xyXG4gICAgICAgIHZhciBmYWN0b3JpZXMgPSBMYXlvdXRFZGl0b3IuZmFjdG9yaWVzID0gTGF5b3V0RWRpdG9yLmZhY3RvcmllcyB8fCB7fTtcclxuICAgICAgICBmYWN0b3JpZXNbdHlwZV0gPSBmYWN0b3J5O1xyXG4gICAgfTtcclxuXHJcbiAgICByZWdpc3RlckZhY3RvcnkoXCJDYW52YXNcIiwgZnVuY3Rpb24gKHZhbHVlKSB7IHJldHVybiBMYXlvdXRFZGl0b3IuQ2FudmFzLmZyb20odmFsdWUpOyB9KTtcclxuICAgIHJlZ2lzdGVyRmFjdG9yeShcIkdyaWRcIiwgZnVuY3Rpb24odmFsdWUpIHsgcmV0dXJuIExheW91dEVkaXRvci5HcmlkLmZyb20odmFsdWUpOyB9KTtcclxuICAgIHJlZ2lzdGVyRmFjdG9yeShcIlJvd1wiLCBmdW5jdGlvbih2YWx1ZSkgeyByZXR1cm4gTGF5b3V0RWRpdG9yLlJvdy5mcm9tKHZhbHVlKTsgfSk7XHJcbiAgICByZWdpc3RlckZhY3RvcnkoXCJDb2x1bW5cIiwgZnVuY3Rpb24odmFsdWUpIHsgcmV0dXJuIExheW91dEVkaXRvci5Db2x1bW4uZnJvbSh2YWx1ZSk7IH0pO1xyXG4gICAgcmVnaXN0ZXJGYWN0b3J5KFwiQ29udGVudFwiLCBmdW5jdGlvbih2YWx1ZSkgeyByZXR1cm4gTGF5b3V0RWRpdG9yLkNvbnRlbnQuZnJvbSh2YWx1ZSk7IH0pO1xyXG5cclxuICAgIExheW91dEVkaXRvci5lbGVtZW50RnJvbSA9IGZ1bmN0aW9uICh2YWx1ZSkge1xyXG4gICAgICAgIHZhciBmYWN0b3J5ID0gTGF5b3V0RWRpdG9yLmZhY3Rvcmllc1t2YWx1ZS50eXBlXTtcclxuXHJcbiAgICAgICAgaWYgKCFmYWN0b3J5KVxyXG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJObyBlbGVtZW50IHdpdGggdHlwZSBcXFwiXCIgKyB2YWx1ZS50eXBlICsgXCJcXFwiIHdhcyBmb3VuZC5cIik7XHJcblxyXG4gICAgICAgIHZhciBlbGVtZW50ID0gZmFjdG9yeSh2YWx1ZSk7XHJcbiAgICAgICAgcmV0dXJuIGVsZW1lbnQ7XHJcbiAgICB9O1xyXG5cclxuICAgIExheW91dEVkaXRvci5zZXRNb2RlbCA9IGZ1bmN0aW9uIChlbGVtZW50U2VsZWN0b3IsIG1vZGVsKSB7XHJcbiAgICAgICAgJChlbGVtZW50U2VsZWN0b3IpLnNjb3BlKCkuZWxlbWVudCA9IG1vZGVsO1xyXG4gICAgfTtcclxuXHJcbiAgICBMYXlvdXRFZGl0b3IuZ2V0TW9kZWwgPSBmdW5jdGlvbiAoZWxlbWVudFNlbGVjdG9yKSB7XHJcbiAgICAgICAgcmV0dXJuICQoZWxlbWVudFNlbGVjdG9yKS5zY29wZSgpLmVsZW1lbnQ7XHJcbiAgICB9O1xyXG5cclxufSkoTGF5b3V0RWRpdG9yIHx8IChMYXlvdXRFZGl0b3IgPSB7fSkpOyIsInZhciBMYXlvdXRFZGl0b3I7XHJcbihmdW5jdGlvbiAoTGF5b3V0RWRpdG9yKSB7XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLkVkaXRvciA9IGZ1bmN0aW9uIChjb25maWcsIGNhbnZhc0RhdGEpIHtcclxuICAgICAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcclxuICAgICAgICB0aGlzLmNhbnZhcyA9IExheW91dEVkaXRvci5DYW52YXMuZnJvbShjYW52YXNEYXRhKTtcclxuICAgICAgICB0aGlzLmluaXRpYWxTdGF0ZSA9IEpTT04uc3RyaW5naWZ5KHRoaXMuY2FudmFzLnRvT2JqZWN0KCkpO1xyXG4gICAgICAgIHRoaXMuYWN0aXZlRWxlbWVudCA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5mb2N1c2VkRWxlbWVudCA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5kcm9wVGFyZ2V0RWxlbWVudCA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5pc0RyYWdnaW5nID0gZmFsc2U7XHJcbiAgICAgICAgdGhpcy5pc1Jlc2l6aW5nID0gZmFsc2U7XHJcbiAgICAgICAgdGhpcy5yZWN5Y2xlQmluID0gbmV3IExheW91dEVkaXRvci5SZWN5Y2xlQmluKCk7XHJcblxyXG4gICAgICAgIHRoaXMucmVzZXRUb29sYm94RWxlbWVudHMgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIHRoaXMudG9vbGJveEVsZW1lbnRzID0gW1xyXG4gICAgICAgICAgICAgICAgTGF5b3V0RWRpdG9yLlJvdy5mcm9tKHtcclxuICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogW11cclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgIF07XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5pc0RpcnR5ID0gZnVuY3Rpb24oKSB7XHJcbiAgICAgICAgICAgIHZhciBjdXJyZW50U3RhdGUgPSBKU09OLnN0cmluZ2lmeSh0aGlzLmNhbnZhcy50b09iamVjdCgpKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuaW5pdGlhbFN0YXRlICE9IGN1cnJlbnRTdGF0ZTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLnJlc2V0VG9vbGJveEVsZW1lbnRzKCk7XHJcbiAgICAgICAgdGhpcy5jYW52YXMuc2V0RWRpdG9yKHRoaXMpO1xyXG4gICAgfTtcclxuXHJcbn0pKExheW91dEVkaXRvciB8fCAoTGF5b3V0RWRpdG9yID0ge30pKTtcclxuIiwidmFyIExheW91dEVkaXRvcjtcclxuKGZ1bmN0aW9uIChMYXlvdXRFZGl0b3IpIHtcclxuXHJcbiAgICBMYXlvdXRFZGl0b3IuUmVjeWNsZUJpbiA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICB0aGlzLmVsZW1lbnRzID0gW107XHJcblxyXG4gICAgICAgIHRoaXMuYWRkID0gZnVuY3Rpb24oZWxlbWVudCkge1xyXG4gICAgICAgICAgICB0aGlzLmVsZW1lbnRzLnB1c2goZWxlbWVudCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy50b09iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHtcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwiUmVjeWNsZUJpblwiLFxyXG4gICAgICAgICAgICAgICAgY2hpbGRyZW46IFtdXHJcbiAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuZWxlbWVudHMubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgICAgICAgIHZhciBlbGVtZW50ID0gdGhpcy5lbGVtZW50c1tpXTtcclxuICAgICAgICAgICAgICAgIHZhciBkdG8gPSBlbGVtZW50LnRvT2JqZWN0KCk7XHJcbiAgICAgICAgICAgICAgICByZXN1bHQuY2hpbGRyZW4ucHVzaChkdG8pO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgICAgIH07XHJcbiAgICB9O1xyXG5cclxufSkoTGF5b3V0RWRpdG9yIHx8IChMYXlvdXRFZGl0b3IgPSB7fSkpO1xyXG4iLCJ2YXIgTGF5b3V0RWRpdG9yO1xyXG4oZnVuY3Rpb24gKExheW91dEVkaXRvcikge1xyXG5cclxuICAgIExheW91dEVkaXRvci5FbGVtZW50ID0gZnVuY3Rpb24gKHR5cGUsIGRhdGEsIGh0bWxJZCwgaHRtbENsYXNzLCBodG1sU3R5bGUsIGlzVGVtcGxhdGVkLCBydWxlKSB7XHJcbiAgICAgICAgaWYgKCF0eXBlKVxyXG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJQYXJhbWV0ZXIgJ3R5cGUnIGlzIHJlcXVpcmVkLlwiKTtcclxuXHJcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xyXG4gICAgICAgIHRoaXMudHlwZSA9IHR5cGU7XHJcbiAgICAgICAgdGhpcy5kYXRhID0gZGF0YTtcclxuICAgICAgICB0aGlzLmh0bWxJZCA9IGh0bWxJZDtcclxuICAgICAgICB0aGlzLmh0bWxDbGFzcyA9IGh0bWxDbGFzcztcclxuICAgICAgICB0aGlzLmh0bWxTdHlsZSA9IGh0bWxTdHlsZTtcclxuICAgICAgICB0aGlzLmlzVGVtcGxhdGVkID0gaXNUZW1wbGF0ZWQ7XHJcbiAgICAgICAgdGhpcy5ydWxlID0gcnVsZTtcclxuXHJcbiAgICAgICAgdGhpcy50ZW1wbGF0ZVN0eWxlcyA9IHt9O1xyXG4gICAgICAgIHRoaXMuZWRpdG9yID0gbnVsbDtcclxuICAgICAgICB0aGlzLnBhcmVudCA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5zZXRJc0ZvY3VzZWRFdmVudEhhbmRsZXJzID0gW107XHJcblxyXG4gICAgICAgIHRoaXMuc2V0RWRpdG9yID0gZnVuY3Rpb24gKGVkaXRvcikge1xyXG4gICAgICAgICAgICB0aGlzLmVkaXRvciA9IGVkaXRvcjtcclxuICAgICAgICAgICAgaWYgKCEhdGhpcy5jaGlsZHJlbiAmJiBfLmlzQXJyYXkodGhpcy5jaGlsZHJlbikpIHtcclxuICAgICAgICAgICAgICAgIF8odGhpcy5jaGlsZHJlbikuZWFjaChmdW5jdGlvbiAoY2hpbGQpIHtcclxuICAgICAgICAgICAgICAgICAgICBjaGlsZC5zZXRFZGl0b3IoZWRpdG9yKTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5zZXRQYXJlbnQgPSBmdW5jdGlvbihwYXJlbnRFbGVtZW50KSB7XHJcbiAgICAgICAgICAgIHRoaXMucGFyZW50ID0gcGFyZW50RWxlbWVudDtcclxuICAgICAgICAgICAgdGhpcy5wYXJlbnQub25DaGlsZEFkZGVkKHRoaXMpO1xyXG5cclxuICAgICAgICAgICAgdmFyIGN1cnJlbnRBbmNlc3RvciA9IHBhcmVudEVsZW1lbnQ7XHJcbiAgICAgICAgICAgIHdoaWxlICghIWN1cnJlbnRBbmNlc3Rvcikge1xyXG4gICAgICAgICAgICAgICAgY3VycmVudEFuY2VzdG9yLm9uRGVzY2VuZGFudEFkZGVkKHRoaXMsIHBhcmVudEVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgY3VycmVudEFuY2VzdG9yID0gY3VycmVudEFuY2VzdG9yLnBhcmVudDtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuc2V0SXNUZW1wbGF0ZWQgPSBmdW5jdGlvbiAodmFsdWUpIHtcclxuICAgICAgICAgICAgdGhpcy5pc1RlbXBsYXRlZCA9IHZhbHVlO1xyXG4gICAgICAgICAgICBpZiAoISF0aGlzLmNoaWxkcmVuICYmIF8uaXNBcnJheSh0aGlzLmNoaWxkcmVuKSkge1xyXG4gICAgICAgICAgICAgICAgXyh0aGlzLmNoaWxkcmVuKS5lYWNoKGZ1bmN0aW9uIChjaGlsZCkge1xyXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkLnNldElzVGVtcGxhdGVkKHZhbHVlKTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5hcHBseUVsZW1lbnRFZGl0b3JNb2RlbCA9IGZ1bmN0aW9uKCkgeyAvKiBWaXJ0dWFsICovIH07XHJcblxyXG4gICAgICAgIHRoaXMuZ2V0SXNBY3RpdmUgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5lZGl0b3IpXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmVkaXRvci5hY3RpdmVFbGVtZW50ID09PSB0aGlzICYmICF0aGlzLmdldElzRm9jdXNlZCgpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuc2V0SXNBY3RpdmUgPSBmdW5jdGlvbiAodmFsdWUpIHtcclxuICAgICAgICAgICAgaWYgKCF0aGlzLmVkaXRvcilcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgaWYgKHRoaXMuZWRpdG9yLmlzRHJhZ2dpbmcgfHwgdGhpcy5lZGl0b3IuaXNSZXNpemluZylcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuXHJcbiAgICAgICAgICAgIGlmICh2YWx1ZSlcclxuICAgICAgICAgICAgICAgIHRoaXMuZWRpdG9yLmFjdGl2ZUVsZW1lbnQgPSB0aGlzO1xyXG4gICAgICAgICAgICBlbHNlXHJcbiAgICAgICAgICAgICAgICB0aGlzLmVkaXRvci5hY3RpdmVFbGVtZW50ID0gdGhpcy5wYXJlbnQ7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5nZXRJc0ZvY3VzZWQgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5lZGl0b3IpXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmVkaXRvci5mb2N1c2VkRWxlbWVudCA9PT0gdGhpcztcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLnNldElzRm9jdXNlZCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKCF0aGlzLmVkaXRvcilcclxuICAgICAgICAgICAgXHRyZXR1cm47XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5jaGlsZHJlbiAmJiB0aGlzLmlzVGVtcGxhdGVkKVxyXG4gICAgICAgICAgICBcdHJldHVybjtcclxuICAgICAgICAgICAgaWYgKHRoaXMuZWRpdG9yLmlzRHJhZ2dpbmcgfHwgdGhpcy5lZGl0b3IuaXNSZXNpemluZylcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuXHJcbiAgICAgICAgICAgIHRoaXMuZWRpdG9yLmZvY3VzZWRFbGVtZW50ID0gdGhpcztcclxuICAgICAgICAgICAgXyh0aGlzLnNldElzRm9jdXNlZEV2ZW50SGFuZGxlcnMpLmVhY2goZnVuY3Rpb24gKGl0ZW0pIHtcclxuICAgICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICAgICAgaXRlbSgpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgY2F0Y2ggKGV4KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gSWdub3JlLlxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmdldElzU2VsZWN0ZWQgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmdldElzRm9jdXNlZCgpKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcblxyXG4gICAgICAgICAgICBpZiAoISF0aGlzLmNoaWxkcmVuICYmIF8uaXNBcnJheSh0aGlzLmNoaWxkcmVuKSkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIF8odGhpcy5jaGlsZHJlbikuYW55KGZ1bmN0aW9uKGNoaWxkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNoaWxkLmdldElzU2VsZWN0ZWQoKTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5nZXRJc0Ryb3BUYXJnZXQgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5lZGl0b3IpXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmVkaXRvci5kcm9wVGFyZ2V0RWxlbWVudCA9PT0gdGhpcztcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMuc2V0SXNEcm9wVGFyZ2V0ID0gZnVuY3Rpb24gKHZhbHVlKSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5lZGl0b3IpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIGlmICh2YWx1ZSlcclxuICAgICAgICAgICAgICAgIHRoaXMuZWRpdG9yLmRyb3BUYXJnZXRFbGVtZW50ID0gdGhpcztcclxuICAgICAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICAgICAgdGhpcy5lZGl0b3IuZHJvcFRhcmdldEVsZW1lbnQgPSBudWxsO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuY2FuRGVsZXRlID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAodGhpcy5pc1RlbXBsYXRlZCB8fCAhdGhpcy5wYXJlbnQpXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuZGVsZXRlID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAoIXRoaXMuY2FuRGVsZXRlKCkpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIHRoaXMucGFyZW50LmRlbGV0ZUNoaWxkKHRoaXMpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuY2FuTW92ZVVwID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAodGhpcy5pc1RlbXBsYXRlZCB8fCAhdGhpcy5wYXJlbnQpXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcmVudC5jYW5Nb3ZlQ2hpbGRVcCh0aGlzKTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLm1vdmVVcCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKCF0aGlzLmNhbk1vdmVVcCgpKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB0aGlzLnBhcmVudC5tb3ZlQ2hpbGRVcCh0aGlzKTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNhbk1vdmVEb3duID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAodGhpcy5pc1RlbXBsYXRlZCB8fCAhdGhpcy5wYXJlbnQpXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcmVudC5jYW5Nb3ZlQ2hpbGREb3duKHRoaXMpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMubW92ZURvd24gPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5jYW5Nb3ZlRG93bigpKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB0aGlzLnBhcmVudC5tb3ZlQ2hpbGREb3duKHRoaXMpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuZWxlbWVudFRvT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICAgICAgdHlwZTogdGhpcy50eXBlLFxyXG4gICAgICAgICAgICAgICAgZGF0YTogdGhpcy5kYXRhLFxyXG4gICAgICAgICAgICAgICAgaHRtbElkOiB0aGlzLmh0bWxJZCxcclxuICAgICAgICAgICAgICAgIGh0bWxDbGFzczogdGhpcy5odG1sQ2xhc3MsXHJcbiAgICAgICAgICAgICAgICBodG1sU3R5bGU6IHRoaXMuaHRtbFN0eWxlLFxyXG4gICAgICAgICAgICAgICAgaXNUZW1wbGF0ZWQ6IHRoaXMuaXNUZW1wbGF0ZWQsXHJcbiAgICAgICAgICAgICAgICBydWxlOiB0aGlzLnJ1bGUsXHJcbiAgICAgICAgICAgICAgICBjb250ZW50VHlwZTogdGhpcy5jb250ZW50VHlwZSxcclxuICAgICAgICAgICAgICAgIGhhc0VkaXRvcjogdGhpcy5oYXNFZGl0b3JcclxuICAgICAgICAgICAgfTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmdldEVkaXRvck9iamVjdCA9IGZ1bmN0aW9uKCkge1xyXG4gICAgICAgICAgICByZXR1cm4ge307XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy50b09iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHNlbGYuZWxlbWVudFRvT2JqZWN0KCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jb3B5ID0gZnVuY3Rpb24gKGNsaXBib2FyZERhdGEpIHtcclxuICAgICAgICAgICAgdmFyIHRleHQgPSB0aGlzLmdldElubmVyVGV4dCgpO1xyXG4gICAgICAgICAgICBjbGlwYm9hcmREYXRhLnNldERhdGEoXCJ0ZXh0L3BsYWluXCIsIHRleHQpO1xyXG5cclxuICAgICAgICAgICAgdmFyIGRhdGEgPSB0aGlzLnRvT2JqZWN0KCk7XHJcbiAgICAgICAgICAgIHZhciBqc29uID0gSlNPTi5zdHJpbmdpZnkoZGF0YSwgbnVsbCwgXCJcXHRcIik7XHJcbiAgICAgICAgICAgIGNsaXBib2FyZERhdGEuc2V0RGF0YShcInRleHQvanNvblwiLCBqc29uKTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmN1dCA9IGZ1bmN0aW9uIChjbGlwYm9hcmREYXRhKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmNhbkRlbGV0ZSgpKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmNvcHkoY2xpcGJvYXJkRGF0YSk7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmRlbGV0ZSgpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5wYXN0ZSA9IGZ1bmN0aW9uIChjbGlwYm9hcmREYXRhKSB7XHJcbiAgICAgICAgICAgIGlmICghIXRoaXMucGFyZW50KVxyXG4gICAgICAgICAgICAgICAgdGhpcy5wYXJlbnQucGFzdGUoY2xpcGJvYXJkRGF0YSk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5nZXRUZW1wbGF0ZVN0eWxlcyA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgdmFyIHN0eWxlcyA9IHRoaXMudGVtcGxhdGVTdHlsZXMgfHwge307XHJcbiAgICAgICAgICAgIHZhciBjc3MgPSBcIlwiO1xyXG5cclxuICAgICAgICAgICAgZm9yICh2YXIgcHJvcGVydHkgaW4gc3R5bGVzKSB7XHJcbiAgICAgICAgICAgICAgICBjc3MgKz0gcHJvcGVydHkgKyBcIjpcIiArIHN0eWxlc1twcm9wZXJ0eV0gKyBcIjtcIjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgcmV0dXJuIGNzcztcclxuICAgICAgICB9XHJcbiAgICB9O1xyXG5cclxufSkoTGF5b3V0RWRpdG9yIHx8IChMYXlvdXRFZGl0b3IgPSB7fSkpOyIsInZhciBMYXlvdXRFZGl0b3I7XHJcbihmdW5jdGlvbiAoTGF5b3V0RWRpdG9yKSB7XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLkNvbnRhaW5lciA9IGZ1bmN0aW9uIChhbGxvd2VkQ2hpbGRUeXBlcywgY2hpbGRyZW4pIHtcclxuXHJcbiAgICAgICAgdGhpcy5hbGxvd2VkQ2hpbGRUeXBlcyA9IGFsbG93ZWRDaGlsZFR5cGVzO1xyXG4gICAgICAgIHRoaXMuY2hpbGRyZW4gPSBjaGlsZHJlbjtcclxuICAgICAgICB0aGlzLmlzQ29udGFpbmVyID0gdHJ1ZTtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lclRlbXBsYXRlU3R5bGVzID0ge307XHJcblxyXG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcclxuXHJcbiAgICAgICAgdGhpcy5vbkNoaWxkQWRkZWQgPSBmdW5jdGlvbiAoZWxlbWVudCkgeyAvKiBWaXJ0dWFsICovIH07XHJcbiAgICAgICAgdGhpcy5vbkRlc2NlbmRhbnRBZGRlZCA9IGZ1bmN0aW9uIChlbGVtZW50LCBwYXJlbnRFbGVtZW50KSB7IC8qIFZpcnR1YWwgKi8gfTtcclxuXHJcbiAgICAgICAgdGhpcy5zZXRDaGlsZHJlbiA9IGZ1bmN0aW9uIChjaGlsZHJlbikge1xyXG4gICAgICAgICAgICB0aGlzLmNoaWxkcmVuID0gY2hpbGRyZW47XHJcbiAgICAgICAgICAgIF8odGhpcy5jaGlsZHJlbikuZWFjaChmdW5jdGlvbiAoY2hpbGQpIHtcclxuICAgICAgICAgICAgICAgIGNoaWxkLnNldFBhcmVudChzZWxmKTtcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5zZXRDaGlsZHJlbihjaGlsZHJlbik7XHJcblxyXG4gICAgICAgIHRoaXMuZ2V0SXNTZWFsZWQgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBfKHRoaXMuY2hpbGRyZW4pLmFueShmdW5jdGlvbiAoY2hpbGQpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybiBjaGlsZC5pc1RlbXBsYXRlZDtcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdmFyIF9iYXNlU2V0SXNGb2N1c2VkID0gdGhpcy5zZXRJc0ZvY3VzZWQ7XHJcbiAgICAgICAgdGhpcy5zZXRJc0ZvY3VzZWQgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmdldElzU2VhbGVkKCkpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIF9iYXNlU2V0SXNGb2N1c2VkLmNhbGwodGhpcyk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5hZGRDaGlsZCA9IGZ1bmN0aW9uIChjaGlsZCkge1xyXG4gICAgICAgICAgICBpZiAoIV8odGhpcy5jaGlsZHJlbikuY29udGFpbnMoY2hpbGQpICYmIChfKHRoaXMuYWxsb3dlZENoaWxkVHlwZXMpLmNvbnRhaW5zKGNoaWxkLnR5cGUpIHx8IGNoaWxkLmlzQ29udGFpbmFibGUpKVxyXG4gICAgICAgICAgICAgICAgdGhpcy5jaGlsZHJlbi5wdXNoKGNoaWxkKTtcclxuICAgICAgICAgICAgY2hpbGQuc2V0RWRpdG9yKHRoaXMuZWRpdG9yKTtcclxuICAgICAgICAgICAgY2hpbGQuc2V0SXNUZW1wbGF0ZWQoZmFsc2UpO1xyXG4gICAgICAgICAgICBjaGlsZC5zZXRQYXJlbnQodGhpcyk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5kZWxldGVDaGlsZCA9IGZ1bmN0aW9uIChjaGlsZCkge1xyXG4gICAgICAgICAgICB2YXIgaW5kZXggPSBfKHRoaXMuY2hpbGRyZW4pLmluZGV4T2YoY2hpbGQpO1xyXG4gICAgICAgICAgICBpZiAoaW5kZXggPj0gMCkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5jaGlsZHJlbi5zcGxpY2UoaW5kZXgsIDEpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5lZGl0b3IucmVjeWNsZUJpbi5hZGQoY2hpbGQpO1xyXG4gICAgICAgICAgICAgICAgaWYgKGNoaWxkLmdldElzQWN0aXZlKCkpXHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lZGl0b3IuYWN0aXZlRWxlbWVudCA9IG51bGw7XHJcbiAgICAgICAgICAgICAgICBpZiAoY2hpbGQuZ2V0SXNGb2N1c2VkKCkpIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBJZiB0aGUgZGVsZXRlZCBjaGlsZCB3YXMgZm9jdXNlZCwgdHJ5IHRvIHNldCBuZXcgZm9jdXMgdG8gdGhlIG1vc3QgYXBwcm9wcmlhdGUgc2libGluZyBvciBwYXJlbnQuXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuY2hpbGRyZW4ubGVuZ3RoID4gaW5kZXgpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2hpbGRyZW5baW5kZXhdLnNldElzRm9jdXNlZCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKGluZGV4ID4gMClcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jaGlsZHJlbltpbmRleCAtIDFdLnNldElzRm9jdXNlZCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIGVsc2VcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRJc0ZvY3VzZWQoKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMubW92ZUZvY3VzUHJldkNoaWxkID0gZnVuY3Rpb24gKGNoaWxkKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmNoaWxkcmVuLmxlbmd0aCA8IDIpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIHZhciBpbmRleCA9IF8odGhpcy5jaGlsZHJlbikuaW5kZXhPZihjaGlsZCk7XHJcbiAgICAgICAgICAgIGlmIChpbmRleCA+IDApXHJcbiAgICAgICAgICAgICAgICB0aGlzLmNoaWxkcmVuW2luZGV4IC0gMV0uc2V0SXNGb2N1c2VkKCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5tb3ZlRm9jdXNOZXh0Q2hpbGQgPSBmdW5jdGlvbiAoY2hpbGQpIHtcclxuICAgICAgICAgICAgaWYgKHRoaXMuY2hpbGRyZW4ubGVuZ3RoIDwgMilcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgdmFyIGluZGV4ID0gXyh0aGlzLmNoaWxkcmVuKS5pbmRleE9mKGNoaWxkKTtcclxuICAgICAgICAgICAgaWYgKGluZGV4IDwgdGhpcy5jaGlsZHJlbi5sZW5ndGggLSAxKVxyXG4gICAgICAgICAgICAgICAgdGhpcy5jaGlsZHJlbltpbmRleCArIDFdLnNldElzRm9jdXNlZCgpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuaW5zZXJ0Q2hpbGQgPSBmdW5jdGlvbiAoY2hpbGQsIGFmdGVyQ2hpbGQpIHtcclxuICAgICAgICAgICAgaWYgKCFfKHRoaXMuY2hpbGRyZW4pLmNvbnRhaW5zKGNoaWxkKSkge1xyXG4gICAgICAgICAgICAgICAgdmFyIGluZGV4ID0gTWF0aC5tYXgoXyh0aGlzLmNoaWxkcmVuKS5pbmRleE9mKGFmdGVyQ2hpbGQpLCAwKTtcclxuICAgICAgICAgICAgICAgIHRoaXMuY2hpbGRyZW4uc3BsaWNlKGluZGV4ICsgMSwgMCwgY2hpbGQpO1xyXG4gICAgICAgICAgICAgICAgY2hpbGQuc2V0RWRpdG9yKHRoaXMuZWRpdG9yKTtcclxuICAgICAgICAgICAgICAgIGNoaWxkLnBhcmVudCA9IHRoaXM7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLm1vdmVDaGlsZFVwID0gZnVuY3Rpb24gKGNoaWxkKSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5jYW5Nb3ZlQ2hpbGRVcChjaGlsZCkpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIHZhciBpbmRleCA9IF8odGhpcy5jaGlsZHJlbikuaW5kZXhPZihjaGlsZCk7XHJcbiAgICAgICAgICAgIHRoaXMuY2hpbGRyZW4ubW92ZShpbmRleCwgaW5kZXggLSAxKTtcclxuICAgICAgICAgICAgJC5ldmVudC50cmlnZ2VyKHtcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwibGF5b3V0ZWRpdG9yOmVkaXRlZFwiXHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMubW92ZUNoaWxkRG93biA9IGZ1bmN0aW9uIChjaGlsZCkge1xyXG4gICAgICAgICAgICBpZiAoIXRoaXMuY2FuTW92ZUNoaWxkRG93bihjaGlsZCkpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIHZhciBpbmRleCA9IF8odGhpcy5jaGlsZHJlbikuaW5kZXhPZihjaGlsZCk7XHJcbiAgICAgICAgICAgIHRoaXMuY2hpbGRyZW4ubW92ZShpbmRleCwgaW5kZXggKyAxKTtcclxuICAgICAgICAgICAgJC5ldmVudC50cmlnZ2VyKHtcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwibGF5b3V0ZWRpdG9yOmVkaXRlZFwiXHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuY2FuTW92ZUNoaWxkVXAgPSBmdW5jdGlvbiAoY2hpbGQpIHtcclxuICAgICAgICAgICAgdmFyIGluZGV4ID0gXyh0aGlzLmNoaWxkcmVuKS5pbmRleE9mKGNoaWxkKTtcclxuICAgICAgICAgICAgcmV0dXJuIGluZGV4ID4gMDtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNhbk1vdmVDaGlsZERvd24gPSBmdW5jdGlvbiAoY2hpbGQpIHtcclxuICAgICAgICAgICAgdmFyIGluZGV4ID0gXyh0aGlzLmNoaWxkcmVuKS5pbmRleE9mKGNoaWxkKTtcclxuICAgICAgICAgICAgcmV0dXJuIGluZGV4IDwgdGhpcy5jaGlsZHJlbi5sZW5ndGggLSAxO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuY2hpbGRyZW5Ub09iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgcmV0dXJuIF8odGhpcy5jaGlsZHJlbikubWFwKGZ1bmN0aW9uIChjaGlsZCkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNoaWxkLnRvT2JqZWN0KCk7XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuZ2V0SW5uZXJUZXh0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICByZXR1cm4gXyh0aGlzLmNoaWxkcmVuKS5yZWR1Y2UoZnVuY3Rpb24gKG1lbW8sIGNoaWxkKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gbWVtbyArIFwiXFxuXCIgKyBjaGlsZC5nZXRJbm5lclRleHQoKTtcclxuICAgICAgICAgICAgfSwgXCJcIik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLnBhc3RlID0gZnVuY3Rpb24gKGNsaXBib2FyZERhdGEpIHtcclxuICAgICAgICAgICAgdmFyIGpzb24gPSBjbGlwYm9hcmREYXRhLmdldERhdGEoXCJ0ZXh0L2pzb25cIik7XHJcbiAgICAgICAgICAgIGlmICghIWpzb24pIHtcclxuICAgICAgICAgICAgICAgIHZhciBkYXRhID0gSlNPTi5wYXJzZShqc29uKTtcclxuICAgICAgICAgICAgICAgIHZhciBjaGlsZCA9IExheW91dEVkaXRvci5lbGVtZW50RnJvbShkYXRhKTtcclxuICAgICAgICAgICAgICAgIHRoaXMucGFzdGVDaGlsZChjaGlsZCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLnBhc3RlQ2hpbGQgPSBmdW5jdGlvbiAoY2hpbGQpIHtcclxuICAgICAgICAgICAgaWYgKF8odGhpcy5hbGxvd2VkQ2hpbGRUeXBlcykuY29udGFpbnMoY2hpbGQudHlwZSkgfHwgY2hpbGQuaXNDb250YWluYWJsZSkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5hZGRDaGlsZChjaGlsZCk7XHJcbiAgICAgICAgICAgICAgICBjaGlsZC5zZXRJc0ZvY3VzZWQoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBlbHNlIGlmICghIXRoaXMucGFyZW50KVxyXG4gICAgICAgICAgICAgICAgdGhpcy5wYXJlbnQucGFzdGVDaGlsZChjaGlsZCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLmdldENvbnRhaW5lclRlbXBsYXRlU3R5bGVzID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICB2YXIgc3R5bGVzID0gdGhpcy5jb250YWluZXJUZW1wbGF0ZVN0eWxlcyB8fCB7fTtcclxuICAgICAgICAgICAgdmFyIGNzcyA9IFwiXCI7XHJcblxyXG4gICAgICAgICAgICBmb3IgKHZhciBwcm9wZXJ0eSBpbiBzdHlsZXMpIHtcclxuICAgICAgICAgICAgICAgIGNzcyArPSBwcm9wZXJ0eSArIFwiOlwiICsgc3R5bGVzW3Byb3BlcnR5XSArIFwiO1wiO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICByZXR1cm4gY3NzO1xyXG4gICAgICAgIH1cclxuICAgIH07XHJcblxyXG59KShMYXlvdXRFZGl0b3IgfHwgKExheW91dEVkaXRvciA9IHt9KSk7IiwidmFyIExheW91dEVkaXRvcjtcclxuKGZ1bmN0aW9uIChMYXlvdXRFZGl0b3IpIHtcclxuXHJcbiAgICBMYXlvdXRFZGl0b3IuQ2FudmFzID0gZnVuY3Rpb24gKGRhdGEsIGh0bWxJZCwgaHRtbENsYXNzLCBodG1sU3R5bGUsIGlzVGVtcGxhdGVkLCBydWxlLCBjaGlsZHJlbikge1xyXG4gICAgICAgIExheW91dEVkaXRvci5FbGVtZW50LmNhbGwodGhpcywgXCJDYW52YXNcIiwgZGF0YSwgaHRtbElkLCBodG1sQ2xhc3MsIGh0bWxTdHlsZSwgaXNUZW1wbGF0ZWQsIHJ1bGUpO1xyXG4gICAgICAgIExheW91dEVkaXRvci5Db250YWluZXIuY2FsbCh0aGlzLCBbXCJDYW52YXNcIiwgXCJHcmlkXCIsIFwiQ29udGVudFwiXSwgY2hpbGRyZW4pO1xyXG5cclxuICAgICAgICB0aGlzLmlzQ29udGFpbmFibGUgPSB0cnVlO1xyXG5cclxuICAgICAgICB0aGlzLnRvT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gdGhpcy5lbGVtZW50VG9PYmplY3QoKTtcclxuICAgICAgICAgICAgcmVzdWx0LmNoaWxkcmVuID0gdGhpcy5jaGlsZHJlblRvT2JqZWN0KCk7XHJcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICAgICAgfTtcclxuICAgIH07XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLkNhbnZhcy5mcm9tID0gZnVuY3Rpb24gKHZhbHVlKSB7XHJcbiAgICAgICAgdmFyIHJlc3VsdCA9IG5ldyBMYXlvdXRFZGl0b3IuQ2FudmFzKFxyXG4gICAgICAgICAgICB2YWx1ZS5kYXRhLFxyXG4gICAgICAgICAgICB2YWx1ZS5odG1sSWQsXHJcbiAgICAgICAgICAgIHZhbHVlLmh0bWxDbGFzcyxcclxuICAgICAgICAgICAgdmFsdWUuaHRtbFN0eWxlLFxyXG4gICAgICAgICAgICB2YWx1ZS5pc1RlbXBsYXRlZCxcclxuICAgICAgICAgICAgdmFsdWUucnVsZSxcclxuICAgICAgICAgICAgTGF5b3V0RWRpdG9yLmNoaWxkcmVuRnJvbSh2YWx1ZS5jaGlsZHJlbikpO1xyXG5cclxuICAgICAgICByZXN1bHQudG9vbGJveEljb24gPSB2YWx1ZS50b29sYm94SWNvbjtcclxuICAgICAgICByZXN1bHQudG9vbGJveExhYmVsID0gdmFsdWUudG9vbGJveExhYmVsO1xyXG4gICAgICAgIHJlc3VsdC50b29sYm94RGVzY3JpcHRpb24gPSB2YWx1ZS50b29sYm94RGVzY3JpcHRpb247XHJcblxyXG4gICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICB9O1xyXG5cclxufSkoTGF5b3V0RWRpdG9yIHx8IChMYXlvdXRFZGl0b3IgPSB7fSkpO1xyXG4iLCJ2YXIgTGF5b3V0RWRpdG9yO1xyXG4oZnVuY3Rpb24gKExheW91dEVkaXRvcikge1xyXG5cclxuICAgIExheW91dEVkaXRvci5HcmlkID0gZnVuY3Rpb24gKGRhdGEsIGh0bWxJZCwgaHRtbENsYXNzLCBodG1sU3R5bGUsIGlzVGVtcGxhdGVkLCBydWxlLCBjaGlsZHJlbikge1xyXG4gICAgICAgIExheW91dEVkaXRvci5FbGVtZW50LmNhbGwodGhpcywgXCJHcmlkXCIsIGRhdGEsIGh0bWxJZCwgaHRtbENsYXNzLCBodG1sU3R5bGUsIGlzVGVtcGxhdGVkLCBydWxlKTtcclxuICAgICAgICBMYXlvdXRFZGl0b3IuQ29udGFpbmVyLmNhbGwodGhpcywgW1wiUm93XCJdLCBjaGlsZHJlbik7XHJcblxyXG4gICAgICAgIHRoaXMudG9PYmplY3QgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIHZhciByZXN1bHQgPSB0aGlzLmVsZW1lbnRUb09iamVjdCgpO1xyXG4gICAgICAgICAgICByZXN1bHQuY2hpbGRyZW4gPSB0aGlzLmNoaWxkcmVuVG9PYmplY3QoKTtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgICAgICB9O1xyXG4gICAgfTtcclxuXHJcbiAgICBMYXlvdXRFZGl0b3IuR3JpZC5mcm9tID0gZnVuY3Rpb24gKHZhbHVlKSB7XHJcbiAgICAgICAgdmFyIHJlc3VsdCA9IG5ldyBMYXlvdXRFZGl0b3IuR3JpZChcclxuICAgICAgICAgICAgdmFsdWUuZGF0YSxcclxuICAgICAgICAgICAgdmFsdWUuaHRtbElkLFxyXG4gICAgICAgICAgICB2YWx1ZS5odG1sQ2xhc3MsXHJcbiAgICAgICAgICAgIHZhbHVlLmh0bWxTdHlsZSxcclxuICAgICAgICAgICAgdmFsdWUuaXNUZW1wbGF0ZWQsXHJcbiAgICAgICAgICAgIHZhbHVlLnJ1bGUsXHJcbiAgICAgICAgICAgIExheW91dEVkaXRvci5jaGlsZHJlbkZyb20odmFsdWUuY2hpbGRyZW4pKTtcclxuICAgICAgICByZXN1bHQudG9vbGJveEljb24gPSB2YWx1ZS50b29sYm94SWNvbjtcclxuICAgICAgICByZXN1bHQudG9vbGJveExhYmVsID0gdmFsdWUudG9vbGJveExhYmVsO1xyXG4gICAgICAgIHJlc3VsdC50b29sYm94RGVzY3JpcHRpb24gPSB2YWx1ZS50b29sYm94RGVzY3JpcHRpb247XHJcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgIH07XHJcblxyXG59KShMYXlvdXRFZGl0b3IgfHwgKExheW91dEVkaXRvciA9IHt9KSk7IiwidmFyIExheW91dEVkaXRvcjtcclxuKGZ1bmN0aW9uIChMYXlvdXRFZGl0b3IpIHtcclxuXHJcbiAgICBMYXlvdXRFZGl0b3IuUm93ID0gZnVuY3Rpb24gKGRhdGEsIGh0bWxJZCwgaHRtbENsYXNzLCBodG1sU3R5bGUsIGlzVGVtcGxhdGVkLCBydWxlLCBjaGlsZHJlbikge1xyXG4gICAgICAgIExheW91dEVkaXRvci5FbGVtZW50LmNhbGwodGhpcywgXCJSb3dcIiwgZGF0YSwgaHRtbElkLCBodG1sQ2xhc3MsIGh0bWxTdHlsZSwgaXNUZW1wbGF0ZWQsIHJ1bGUpO1xyXG4gICAgICAgIExheW91dEVkaXRvci5Db250YWluZXIuY2FsbCh0aGlzLCBbXCJDb2x1bW5cIl0sIGNoaWxkcmVuKTtcclxuXHJcbiAgICAgICAgdmFyIF9zZWxmID0gdGhpcztcclxuXHJcbiAgICAgICAgZnVuY3Rpb24gX2dldFRvdGFsQ29sdW1uc1dpZHRoKCkge1xyXG4gICAgICAgICAgICByZXR1cm4gXyhfc2VsZi5jaGlsZHJlbikucmVkdWNlKGZ1bmN0aW9uIChtZW1vLCBjaGlsZCkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lbW8gKyBjaGlsZC5vZmZzZXQgKyBjaGlsZC53aWR0aDtcclxuICAgICAgICAgICAgfSwgMCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBJbXBsZW1lbnRzIGEgc2ltcGxlIGFsZ29yaXRobSB0byBkaXN0cmlidXRlIHNwYWNlIChlaXRoZXIgcG9zaXRpdmUgb3IgbmVnYXRpdmUpXHJcbiAgICAgICAgLy8gYmV0d2VlbiB0aGUgY2hpbGQgY29sdW1ucyBvZiB0aGUgcm93LiBOZWdhdGl2ZSBzcGFjZSBpcyBkaXN0cmlidXRlZCB3aGVuIG1ha2luZ1xyXG4gICAgICAgIC8vIHJvb20gZm9yIGEgbmV3IGNvbHVtbiAoZS5jLiBjbGlwYm9hcmQgcGFzdGUgb3IgZHJvcHBpbmcgZnJvbSB0aGUgdG9vbGJveCkgd2hpbGVcclxuICAgICAgICAvLyBwb3NpdGl2ZSBzcGFjZSBpcyBkaXN0cmlidXRlZCB3aGVuIGZpbGxpbmcgdGhlIGdyYXAgb2YgYSByZW1vdmVkIGNvbHVtbi5cclxuICAgICAgICBmdW5jdGlvbiBfZGlzdHJpYnV0ZVNwYWNlKHNwYWNlKSB7XHJcbiAgICAgICAgICAgIGlmIChzcGFjZSA9PSAwKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICAgICBcclxuICAgICAgICAgICAgdmFyIHVuZGlzdHJpYnV0ZWRTcGFjZSA9IHNwYWNlO1xyXG5cclxuICAgICAgICAgICAgaWYgKHVuZGlzdHJpYnV0ZWRTcGFjZSA8IDApIHtcclxuICAgICAgICAgICAgICAgIHZhciB2YWNhbnRTcGFjZSA9IDEyIC0gX2dldFRvdGFsQ29sdW1uc1dpZHRoKCk7XHJcbiAgICAgICAgICAgICAgICB1bmRpc3RyaWJ1dGVkU3BhY2UgKz0gdmFjYW50U3BhY2U7XHJcbiAgICAgICAgICAgICAgICBpZiAodW5kaXN0cmlidXRlZFNwYWNlID4gMClcclxuICAgICAgICAgICAgICAgICAgICB1bmRpc3RyaWJ1dGVkU3BhY2UgPSAwO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBJZiBzcGFjZSBpcyBuZWdhdGl2ZSwgdHJ5IHRvIGRlY3JlYXNlIG9mZnNldHMgZmlyc3QuXHJcbiAgICAgICAgICAgIHdoaWxlICh1bmRpc3RyaWJ1dGVkU3BhY2UgPCAwICYmIF8oX3NlbGYuY2hpbGRyZW4pLmFueShmdW5jdGlvbiAoY29sdW1uKSB7IHJldHVybiBjb2x1bW4ub2Zmc2V0ID4gMDsgfSkpIHsgLy8gV2hpbGUgdGhlcmUgaXMgc3RpbGwgb2Zmc2V0IGxlZnQgdG8gcmVtb3ZlLlxyXG4gICAgICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IF9zZWxmLmNoaWxkcmVuLmxlbmd0aCAmJiB1bmRpc3RyaWJ1dGVkU3BhY2UgPCAwOyBpKyspIHtcclxuICAgICAgICAgICAgICAgICAgICB2YXIgY29sdW1uID0gX3NlbGYuY2hpbGRyZW5baV07XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbHVtbi5vZmZzZXQgPiAwKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbi5vZmZzZXQtLTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdW5kaXN0cmlidXRlZFNwYWNlKys7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBmdW5jdGlvbiBoYXNXaWR0aChjb2x1bW4pIHtcclxuICAgICAgICAgICAgICAgIGlmICh1bmRpc3RyaWJ1dGVkU3BhY2UgPiAwKVxyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBjb2x1bW4ud2lkdGggPCAxMjtcclxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKHVuZGlzdHJpYnV0ZWRTcGFjZSA8IDApXHJcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNvbHVtbi53aWR0aCA+IDE7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIFRyeSB0byBkaXN0cmlidXRlIHJlbWFpbmluZyBzcGFjZSAoY291bGQgYmUgbmVnYXRpdmUgb3IgcG9zaXRpdmUpIHVzaW5nIHdpZHRocy5cclxuICAgICAgICAgICAgd2hpbGUgKHVuZGlzdHJpYnV0ZWRTcGFjZSAhPSAwKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBBbnkgbW9yZSBjb2x1bW4gd2lkdGggYXZhaWxhYmxlIGZvciBkaXN0cmlidXRpb24/XHJcbiAgICAgICAgICAgICAgICBpZiAoIV8oX3NlbGYuY2hpbGRyZW4pLmFueShoYXNXaWR0aCkpXHJcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgX3NlbGYuY2hpbGRyZW4ubGVuZ3RoICYmIHVuZGlzdHJpYnV0ZWRTcGFjZSAhPSAwOyBpKyspIHtcclxuICAgICAgICAgICAgICAgICAgICB2YXIgY29sdW1uID0gX3NlbGYuY2hpbGRyZW5baSAlIF9zZWxmLmNoaWxkcmVuLmxlbmd0aF07XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKGhhc1dpZHRoKGNvbHVtbikpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGRlbHRhID0gdW5kaXN0cmlidXRlZFNwYWNlIC8gTWF0aC5hYnModW5kaXN0cmlidXRlZFNwYWNlKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uLndpZHRoICs9IGRlbHRhO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB1bmRpc3RyaWJ1dGVkU3BhY2UgLT0gZGVsdGE7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfSAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgcmV0dXJuIHVuZGlzdHJpYnV0ZWRTcGFjZSA9PSAwO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdmFyIF9pc0FkZGluZ0NvbHVtbiA9IGZhbHNlO1xyXG5cclxuICAgICAgICB0aGlzLmNhbkFkZENvbHVtbiA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY2hpbGRyZW4ubGVuZ3RoIDwgMTI7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5iZWdpbkFkZENvbHVtbiA9IGZ1bmN0aW9uIChuZXdDb2x1bW5XaWR0aCkge1xyXG4gICAgICAgICAgICBpZiAoISFfaXNBZGRpbmdDb2x1bW4pXHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb2x1bW4gYWRkIG9wZXJhdGlvbiBpcyBhbHJlYWR5IGluIHByb2dyZXNzLlwiKVxyXG4gICAgICAgICAgICBfKHRoaXMuY2hpbGRyZW4pLmVhY2goZnVuY3Rpb24gKGNvbHVtbikge1xyXG4gICAgICAgICAgICAgICAgY29sdW1uLmJlZ2luQ2hhbmdlKCk7XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICBpZiAoX2Rpc3RyaWJ1dGVTcGFjZSgtbmV3Q29sdW1uV2lkdGgpKSB7XHJcbiAgICAgICAgICAgICAgICBfaXNBZGRpbmdDb2x1bW4gPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgXyh0aGlzLmNoaWxkcmVuKS5lYWNoKGZ1bmN0aW9uIChjb2x1bW4pIHtcclxuICAgICAgICAgICAgICAgIGNvbHVtbi5yb2xsYmFja0NoYW5nZSgpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuY29tbWl0QWRkQ29sdW1uID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAoIV9pc0FkZGluZ0NvbHVtbilcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk5vIGNvbHVtbiBhZGQgb3BlcmF0aW9uIGluIHByb2dyZXNzLlwiKVxyXG4gICAgICAgICAgICBfKHRoaXMuY2hpbGRyZW4pLmVhY2goZnVuY3Rpb24gKGNvbHVtbikge1xyXG4gICAgICAgICAgICAgICAgY29sdW1uLmNvbW1pdENoYW5nZSgpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgX2lzQWRkaW5nQ29sdW1uID0gZmFsc2U7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5yb2xsYmFja0FkZENvbHVtbiA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKCFfaXNBZGRpbmdDb2x1bW4pXHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJObyBjb2x1bW4gYWRkIG9wZXJhdGlvbiBpbiBwcm9ncmVzcy5cIilcclxuICAgICAgICAgICAgXyh0aGlzLmNoaWxkcmVuKS5lYWNoKGZ1bmN0aW9uIChjb2x1bW4pIHtcclxuICAgICAgICAgICAgICAgIGNvbHVtbi5yb2xsYmFja0NoYW5nZSgpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgX2lzQWRkaW5nQ29sdW1uID0gZmFsc2U7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdmFyIF9iYXNlRGVsZXRlQ2hpbGQgPSB0aGlzLmRlbGV0ZUNoaWxkO1xyXG4gICAgICAgIHRoaXMuZGVsZXRlQ2hpbGQgPSBmdW5jdGlvbiAoY29sdW1uKSB7IFxyXG4gICAgICAgICAgICB2YXIgd2lkdGggPSBjb2x1bW4ud2lkdGg7XHJcbiAgICAgICAgICAgIF9iYXNlRGVsZXRlQ2hpbGQuY2FsbCh0aGlzLCBjb2x1bW4pO1xyXG4gICAgICAgICAgICBfZGlzdHJpYnV0ZVNwYWNlKHdpZHRoKTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNhbkNvbnRyYWN0Q29sdW1uUmlnaHQgPSBmdW5jdGlvbiAoY29sdW1uLCBjb25uZWN0QWRqYWNlbnQpIHtcclxuICAgICAgICAgICAgdmFyIGluZGV4ID0gXyh0aGlzLmNoaWxkcmVuKS5pbmRleE9mKGNvbHVtbik7XHJcbiAgICAgICAgICAgIGlmIChpbmRleCA+PSAwKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNvbHVtbi53aWR0aCA+IDE7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNvbnRyYWN0Q29sdW1uUmlnaHQgPSBmdW5jdGlvbiAoY29sdW1uLCBjb25uZWN0QWRqYWNlbnQpIHtcclxuICAgICAgICAgICAgaWYgKCF0aGlzLmNhbkNvbnRyYWN0Q29sdW1uUmlnaHQoY29sdW1uLCBjb25uZWN0QWRqYWNlbnQpKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG5cclxuICAgICAgICAgICAgdmFyIGluZGV4ID0gXyh0aGlzLmNoaWxkcmVuKS5pbmRleE9mKGNvbHVtbik7XHJcbiAgICAgICAgICAgIGlmIChpbmRleCA+PSAwKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoY29sdW1uLndpZHRoID4gMSkge1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbHVtbi53aWR0aC0tO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmNoaWxkcmVuLmxlbmd0aCA+IGluZGV4ICsgMSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgbmV4dENvbHVtbiA9IHRoaXMuY2hpbGRyZW5baW5kZXggKyAxXTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNvbm5lY3RBZGphY2VudCAmJiBuZXh0Q29sdW1uLm9mZnNldCA9PSAwKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV4dENvbHVtbi53aWR0aCsrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXh0Q29sdW1uLm9mZnNldCsrO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuY2FuRXhwYW5kQ29sdW1uUmlnaHQgPSBmdW5jdGlvbiAoY29sdW1uLCBjb25uZWN0QWRqYWNlbnQpIHtcclxuICAgICAgICAgICAgdmFyIGluZGV4ID0gXyh0aGlzLmNoaWxkcmVuKS5pbmRleE9mKGNvbHVtbik7XHJcbiAgICAgICAgICAgIGlmIChpbmRleCA+PSAwKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoY29sdW1uLndpZHRoID49IDEyKVxyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmNoaWxkcmVuLmxlbmd0aCA+IGluZGV4ICsgMSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciBuZXh0Q29sdW1uID0gdGhpcy5jaGlsZHJlbltpbmRleCArIDFdO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChjb25uZWN0QWRqYWNlbnQgJiYgbmV4dENvbHVtbi5vZmZzZXQgPT0gMClcclxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5leHRDb2x1bW4ud2lkdGggPiAxO1xyXG4gICAgICAgICAgICAgICAgICAgIGVsc2VcclxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5leHRDb2x1bW4ub2Zmc2V0ID4gMDtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIHJldHVybiBfZ2V0VG90YWxDb2x1bW5zV2lkdGgoKSA8IDEyO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmV4cGFuZENvbHVtblJpZ2h0ID0gZnVuY3Rpb24gKGNvbHVtbiwgY29ubmVjdEFkamFjZW50KSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5jYW5FeHBhbmRDb2x1bW5SaWdodChjb2x1bW4sIGNvbm5lY3RBZGphY2VudCkpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcblxyXG4gICAgICAgICAgICB2YXIgaW5kZXggPSBfKHRoaXMuY2hpbGRyZW4pLmluZGV4T2YoY29sdW1uKTtcclxuICAgICAgICAgICAgaWYgKGluZGV4ID49IDApIHtcclxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmNoaWxkcmVuLmxlbmd0aCA+IGluZGV4ICsgMSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciBuZXh0Q29sdW1uID0gdGhpcy5jaGlsZHJlbltpbmRleCArIDFdO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChjb25uZWN0QWRqYWNlbnQgJiYgbmV4dENvbHVtbi5vZmZzZXQgPT0gMClcclxuICAgICAgICAgICAgICAgICAgICAgICAgbmV4dENvbHVtbi53aWR0aC0tO1xyXG4gICAgICAgICAgICAgICAgICAgIGVsc2VcclxuICAgICAgICAgICAgICAgICAgICAgICAgbmV4dENvbHVtbi5vZmZzZXQtLTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGNvbHVtbi53aWR0aCsrO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jYW5FeHBhbmRDb2x1bW5MZWZ0ID0gZnVuY3Rpb24gKGNvbHVtbiwgY29ubmVjdEFkamFjZW50KSB7XHJcbiAgICAgICAgICAgIHZhciBpbmRleCA9IF8odGhpcy5jaGlsZHJlbikuaW5kZXhPZihjb2x1bW4pO1xyXG4gICAgICAgICAgICBpZiAoaW5kZXggPj0gMCkge1xyXG4gICAgICAgICAgICAgICAgaWYgKGNvbHVtbi53aWR0aCA+PSAxMilcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgICAgICBpZiAoaW5kZXggPiAwKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdmFyIHByZXZDb2x1bW4gPSB0aGlzLmNoaWxkcmVuW2luZGV4IC0gMV07XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbm5lY3RBZGphY2VudCAmJiBjb2x1bW4ub2Zmc2V0ID09IDApXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBwcmV2Q29sdW1uLndpZHRoID4gMTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIHJldHVybiBjb2x1bW4ub2Zmc2V0ID4gMDtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5leHBhbmRDb2x1bW5MZWZ0ID0gZnVuY3Rpb24gKGNvbHVtbiwgY29ubmVjdEFkamFjZW50KSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5jYW5FeHBhbmRDb2x1bW5MZWZ0KGNvbHVtbiwgY29ubmVjdEFkamFjZW50KSlcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuXHJcbiAgICAgICAgICAgIHZhciBpbmRleCA9IF8odGhpcy5jaGlsZHJlbikuaW5kZXhPZihjb2x1bW4pO1xyXG4gICAgICAgICAgICBpZiAoaW5kZXggPj0gMCkge1xyXG4gICAgICAgICAgICAgICAgaWYgKGluZGV4ID4gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciBwcmV2Q29sdW1uID0gdGhpcy5jaGlsZHJlbltpbmRleCAtIDFdO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChjb25uZWN0QWRqYWNlbnQgJiYgY29sdW1uLm9mZnNldCA9PSAwKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICBwcmV2Q29sdW1uLndpZHRoLS07XHJcbiAgICAgICAgICAgICAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW4ub2Zmc2V0LS07XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBlbHNlXHJcbiAgICAgICAgICAgICAgICAgICAgY29sdW1uLm9mZnNldC0tO1xyXG4gICAgICAgICAgICAgICAgY29sdW1uLndpZHRoKys7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNhbkNvbnRyYWN0Q29sdW1uTGVmdCA9IGZ1bmN0aW9uIChjb2x1bW4sIGNvbm5lY3RBZGphY2VudCkge1xyXG4gICAgICAgICAgICB2YXIgaW5kZXggPSBfKHRoaXMuY2hpbGRyZW4pLmluZGV4T2YoY29sdW1uKTtcclxuICAgICAgICAgICAgaWYgKGluZGV4ID49IDApXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gY29sdW1uLndpZHRoID4gMTtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuY29udHJhY3RDb2x1bW5MZWZ0ID0gZnVuY3Rpb24gKGNvbHVtbiwgY29ubmVjdEFkamFjZW50KSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5jYW5Db250cmFjdENvbHVtbkxlZnQoY29sdW1uLCBjb25uZWN0QWRqYWNlbnQpKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG5cclxuICAgICAgICAgICAgdmFyIGluZGV4ID0gXyh0aGlzLmNoaWxkcmVuKS5pbmRleE9mKGNvbHVtbik7XHJcbiAgICAgICAgICAgIGlmIChpbmRleCA+PSAwKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoaW5kZXggPiAwKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdmFyIHByZXZDb2x1bW4gPSB0aGlzLmNoaWxkcmVuW2luZGV4IC0gMV07XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbm5lY3RBZGphY2VudCAmJiBjb2x1bW4ub2Zmc2V0ID09IDApXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHByZXZDb2x1bW4ud2lkdGgrKztcclxuICAgICAgICAgICAgICAgICAgICBlbHNlXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbi5vZmZzZXQrKztcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGVsc2VcclxuICAgICAgICAgICAgICAgICAgICBjb2x1bW4ub2Zmc2V0Kys7XHJcbiAgICAgICAgICAgICAgICBjb2x1bW4ud2lkdGgtLTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMuZXZlbkNvbHVtbnMgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmNoaWxkcmVuLmxlbmd0aCA9PSAwKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG5cclxuICAgICAgICAgICAgdmFyIGV2ZW5XaWR0aCA9IE1hdGguZmxvb3IoMTIgLyB0aGlzLmNoaWxkcmVuLmxlbmd0aCk7XHJcbiAgICAgICAgICAgIF8odGhpcy5jaGlsZHJlbikuZWFjaChmdW5jdGlvbiAoY29sdW1uKSB7XHJcbiAgICAgICAgICAgICAgICBjb2x1bW4ud2lkdGggPSBldmVuV2lkdGg7XHJcbiAgICAgICAgICAgICAgICBjb2x1bW4ub2Zmc2V0ID0gMDtcclxuICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgICB2YXIgcmVzdCA9IDEyICUgdGhpcy5jaGlsZHJlbi5sZW5ndGg7XHJcbiAgICAgICAgICAgIGlmIChyZXN0ID4gMClcclxuICAgICAgICAgICAgICAgIF9kaXN0cmlidXRlU3BhY2UocmVzdCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdmFyIF9iYXNlUGFzdGVDaGlsZCA9IHRoaXMucGFzdGVDaGlsZDtcclxuICAgICAgICB0aGlzLnBhc3RlQ2hpbGQgPSBmdW5jdGlvbiAoY2hpbGQpIHtcclxuICAgICAgICAgICAgaWYgKGNoaWxkLnR5cGUgPT0gXCJDb2x1bW5cIikge1xyXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuYmVnaW5BZGRDb2x1bW4oY2hpbGQud2lkdGgpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21taXRBZGRDb2x1bW4oKTtcclxuICAgICAgICAgICAgICAgICAgICBfYmFzZVBhc3RlQ2hpbGQuY2FsbCh0aGlzLCBjaGlsZClcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBlbHNlIGlmICghIXRoaXMucGFyZW50KVxyXG4gICAgICAgICAgICAgICAgdGhpcy5wYXJlbnQucGFzdGVDaGlsZChjaGlsZCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLnRvT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gdGhpcy5lbGVtZW50VG9PYmplY3QoKTtcclxuICAgICAgICAgICAgcmVzdWx0LmNoaWxkcmVuID0gdGhpcy5jaGlsZHJlblRvT2JqZWN0KCk7XHJcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICAgICAgfTtcclxuICAgIH07XHJcblxyXG4gICAgTGF5b3V0RWRpdG9yLlJvdy5mcm9tID0gZnVuY3Rpb24gKHZhbHVlKSB7XHJcbiAgICAgICAgdmFyIHJlc3VsdCA9IG5ldyBMYXlvdXRFZGl0b3IuUm93KFxyXG4gICAgICAgICAgICB2YWx1ZS5kYXRhLFxyXG4gICAgICAgICAgICB2YWx1ZS5odG1sSWQsXHJcbiAgICAgICAgICAgIHZhbHVlLmh0bWxDbGFzcyxcclxuICAgICAgICAgICAgdmFsdWUuaHRtbFN0eWxlLFxyXG4gICAgICAgICAgICB2YWx1ZS5pc1RlbXBsYXRlZCxcclxuICAgICAgICAgICAgdmFsdWUucnVsZSxcclxuICAgICAgICAgICAgTGF5b3V0RWRpdG9yLmNoaWxkcmVuRnJvbSh2YWx1ZS5jaGlsZHJlbikpO1xyXG4gICAgICAgIHJlc3VsdC50b29sYm94SWNvbiA9IHZhbHVlLnRvb2xib3hJY29uO1xyXG4gICAgICAgIHJlc3VsdC50b29sYm94TGFiZWwgPSB2YWx1ZS50b29sYm94TGFiZWw7XHJcbiAgICAgICAgcmVzdWx0LnRvb2xib3hEZXNjcmlwdGlvbiA9IHZhbHVlLnRvb2xib3hEZXNjcmlwdGlvbjtcclxuICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgfTtcclxuXHJcbn0pKExheW91dEVkaXRvciB8fCAoTGF5b3V0RWRpdG9yID0ge30pKTsiLCJ2YXIgTGF5b3V0RWRpdG9yO1xyXG4oZnVuY3Rpb24gKExheW91dEVkaXRvcikge1xyXG4gICAgTGF5b3V0RWRpdG9yLkNvbHVtbiA9IGZ1bmN0aW9uIChkYXRhLCBodG1sSWQsIGh0bWxDbGFzcywgaHRtbFN0eWxlLCBpc1RlbXBsYXRlZCwgd2lkdGgsIG9mZnNldCwgY29sbGFwc2libGUsIHJ1bGUsIGNoaWxkcmVuKSB7XHJcbiAgICAgICAgTGF5b3V0RWRpdG9yLkVsZW1lbnQuY2FsbCh0aGlzLCBcIkNvbHVtblwiLCBkYXRhLCBodG1sSWQsIGh0bWxDbGFzcywgaHRtbFN0eWxlLCBpc1RlbXBsYXRlZCwgcnVsZSk7XHJcbiAgICAgICAgTGF5b3V0RWRpdG9yLkNvbnRhaW5lci5jYWxsKHRoaXMsIFtcIkdyaWRcIiwgXCJDb250ZW50XCJdLCBjaGlsZHJlbik7XHJcblxyXG4gICAgICAgIHRoaXMud2lkdGggPSB3aWR0aDtcclxuICAgICAgICB0aGlzLm9mZnNldCA9IG9mZnNldDtcclxuICAgICAgICB0aGlzLmNvbGxhcHNpYmxlID0gY29sbGFwc2libGU7XHJcblxyXG4gICAgICAgIHZhciBfaGFzUGVuZGluZ0NoYW5nZSA9IGZhbHNlO1xyXG4gICAgICAgIHZhciBfb3JpZ1dpZHRoID0gMDtcclxuICAgICAgICB2YXIgX29yaWdPZmZzZXQgPSAwO1xyXG5cclxuICAgICAgICB0aGlzLmJlZ2luQ2hhbmdlID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAoISFfaGFzUGVuZGluZ0NoYW5nZSlcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNvbHVtbiBhbHJlYWR5IGhhcyBhIHBlbmRpbmcgY2hhbmdlLlwiKTtcclxuICAgICAgICAgICAgX2hhc1BlbmRpbmdDaGFuZ2UgPSB0cnVlO1xyXG4gICAgICAgICAgICBfb3JpZ1dpZHRoID0gdGhpcy53aWR0aDtcclxuICAgICAgICAgICAgX29yaWdPZmZzZXQgPSB0aGlzLm9mZnNldDtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNvbW1pdENoYW5nZSA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKCFfaGFzUGVuZGluZ0NoYW5nZSlcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNvbHVtbiBoYXMgbm8gcGVuZGluZyBjaGFuZ2UuXCIpO1xyXG4gICAgICAgICAgICBfb3JpZ1dpZHRoID0gMDtcclxuICAgICAgICAgICAgX29yaWdPZmZzZXQgPSAwO1xyXG4gICAgICAgICAgICBfaGFzUGVuZGluZ0NoYW5nZSA9IGZhbHNlO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMucm9sbGJhY2tDaGFuZ2UgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICghX2hhc1BlbmRpbmdDaGFuZ2UpXHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb2x1bW4gaGFzIG5vIHBlbmRpbmcgY2hhbmdlLlwiKTtcclxuICAgICAgICAgICAgdGhpcy53aWR0aCA9IF9vcmlnV2lkdGg7XHJcbiAgICAgICAgICAgIHRoaXMub2Zmc2V0ID0gX29yaWdPZmZzZXQ7XHJcbiAgICAgICAgICAgIF9vcmlnV2lkdGggPSAwO1xyXG4gICAgICAgICAgICBfb3JpZ09mZnNldCA9IDA7XHJcbiAgICAgICAgICAgIF9oYXNQZW5kaW5nQ2hhbmdlID0gZmFsc2U7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jYW5TcGxpdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKHRoaXMuaXNUZW1wbGF0ZWQpXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLndpZHRoID4gMTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLnNwbGl0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAoIXRoaXMuY2FuU3BsaXQoKSlcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuXHJcbiAgICAgICAgICAgIHZhciBuZXdDb2x1bW5XaWR0aCA9IE1hdGguZmxvb3IodGhpcy53aWR0aCAvIDIpO1xyXG4gICAgICAgICAgICB2YXIgbmV3Q29sdW1uID0gTGF5b3V0RWRpdG9yLkNvbHVtbi5mcm9tKHtcclxuICAgICAgICAgICAgICAgIGRhdGE6IG51bGwsXHJcbiAgICAgICAgICAgICAgICBodG1sSWQ6IG51bGwsXHJcbiAgICAgICAgICAgICAgICBodG1sQ2xhc3M6IG51bGwsXHJcbiAgICAgICAgICAgICAgICBodG1sU3R5bGU6IG51bGwsXHJcbiAgICAgICAgICAgICAgICB3aWR0aDogbmV3Q29sdW1uV2lkdGgsXHJcbiAgICAgICAgICAgICAgICBvZmZzZXQ6IDAsXHJcbiAgICAgICAgICAgICAgICBjaGlsZHJlbjogW11cclxuICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgICB0aGlzLndpZHRoID0gdGhpcy53aWR0aCAtIG5ld0NvbHVtbldpZHRoO1xyXG4gICAgICAgICAgICB0aGlzLnBhcmVudC5pbnNlcnRDaGlsZChuZXdDb2x1bW4sIHRoaXMpO1xyXG4gICAgICAgICAgICBuZXdDb2x1bW4uc2V0SXNGb2N1c2VkKCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jYW5Db250cmFjdFJpZ2h0ID0gZnVuY3Rpb24gKGNvbm5lY3RBZGphY2VudCkge1xyXG4gICAgICAgICAgICBpZiAodGhpcy5pc1RlbXBsYXRlZClcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMucGFyZW50LmNhbkNvbnRyYWN0Q29sdW1uUmlnaHQodGhpcywgY29ubmVjdEFkamFjZW50KTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNvbnRyYWN0UmlnaHQgPSBmdW5jdGlvbiAoY29ubmVjdEFkamFjZW50KSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5jYW5Db250cmFjdFJpZ2h0KGNvbm5lY3RBZGphY2VudCkpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIHRoaXMucGFyZW50LmNvbnRyYWN0Q29sdW1uUmlnaHQodGhpcywgY29ubmVjdEFkamFjZW50KTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNhbkV4cGFuZFJpZ2h0ID0gZnVuY3Rpb24gKGNvbm5lY3RBZGphY2VudCkge1xyXG4gICAgICAgICAgICBpZiAodGhpcy5pc1RlbXBsYXRlZClcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMucGFyZW50LmNhbkV4cGFuZENvbHVtblJpZ2h0KHRoaXMsIGNvbm5lY3RBZGphY2VudCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5leHBhbmRSaWdodCA9IGZ1bmN0aW9uIChjb25uZWN0QWRqYWNlbnQpIHtcclxuICAgICAgICAgICAgaWYgKCF0aGlzLmNhbkV4cGFuZFJpZ2h0KGNvbm5lY3RBZGphY2VudCkpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIHRoaXMucGFyZW50LmV4cGFuZENvbHVtblJpZ2h0KHRoaXMsIGNvbm5lY3RBZGphY2VudCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5jYW5FeHBhbmRMZWZ0ID0gZnVuY3Rpb24gKGNvbm5lY3RBZGphY2VudCkge1xyXG4gICAgICAgICAgICBpZiAodGhpcy5pc1RlbXBsYXRlZClcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMucGFyZW50LmNhbkV4cGFuZENvbHVtbkxlZnQodGhpcywgY29ubmVjdEFkamFjZW50KTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmV4cGFuZExlZnQgPSBmdW5jdGlvbiAoY29ubmVjdEFkamFjZW50KSB7XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5jYW5FeHBhbmRMZWZ0KGNvbm5lY3RBZGphY2VudCkpXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIHRoaXMucGFyZW50LmV4cGFuZENvbHVtbkxlZnQodGhpcywgY29ubmVjdEFkamFjZW50KTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNhbkNvbnRyYWN0TGVmdCA9IGZ1bmN0aW9uIChjb25uZWN0QWRqYWNlbnQpIHtcclxuICAgICAgICAgICAgaWYgKHRoaXMuaXNUZW1wbGF0ZWQpXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBhcmVudC5jYW5Db250cmFjdENvbHVtbkxlZnQodGhpcywgY29ubmVjdEFkamFjZW50KTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLmNvbnRyYWN0TGVmdCA9IGZ1bmN0aW9uIChjb25uZWN0QWRqYWNlbnQpIHtcclxuICAgICAgICAgICAgaWYgKCF0aGlzLmNhbkNvbnRyYWN0TGVmdChjb25uZWN0QWRqYWNlbnQpKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB0aGlzLnBhcmVudC5jb250cmFjdENvbHVtbkxlZnQodGhpcywgY29ubmVjdEFkamFjZW50KTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICB0aGlzLnRvT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gdGhpcy5lbGVtZW50VG9PYmplY3QoKTtcclxuICAgICAgICAgICAgcmVzdWx0LndpZHRoID0gdGhpcy53aWR0aDtcclxuICAgICAgICAgICAgcmVzdWx0Lm9mZnNldCA9IHRoaXMub2Zmc2V0O1xyXG4gICAgICAgICAgICByZXN1bHQuY29sbGFwc2libGUgPSB0aGlzLmNvbGxhcHNpYmxlO1xyXG4gICAgICAgICAgICByZXN1bHQuY2hpbGRyZW4gPSB0aGlzLmNoaWxkcmVuVG9PYmplY3QoKTtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgICAgICB9O1xyXG4gICAgfTtcclxuXHJcbiAgICBMYXlvdXRFZGl0b3IuQ29sdW1uLmZyb20gPSBmdW5jdGlvbiAodmFsdWUpIHtcclxuICAgICAgICB2YXIgcmVzdWx0ID0gbmV3IExheW91dEVkaXRvci5Db2x1bW4oXHJcbiAgICAgICAgICAgIHZhbHVlLmRhdGEsXHJcbiAgICAgICAgICAgIHZhbHVlLmh0bWxJZCxcclxuICAgICAgICAgICAgdmFsdWUuaHRtbENsYXNzLFxyXG4gICAgICAgICAgICB2YWx1ZS5odG1sU3R5bGUsXHJcbiAgICAgICAgICAgIHZhbHVlLmlzVGVtcGxhdGVkLFxyXG4gICAgICAgICAgICB2YWx1ZS53aWR0aCxcclxuICAgICAgICAgICAgdmFsdWUub2Zmc2V0LFxyXG4gICAgICAgICAgICB2YWx1ZS5jb2xsYXBzaWJsZSxcclxuICAgICAgICAgICAgdmFsdWUucnVsZSxcclxuICAgICAgICAgICAgTGF5b3V0RWRpdG9yLmNoaWxkcmVuRnJvbSh2YWx1ZS5jaGlsZHJlbikpO1xyXG4gICAgICAgIHJlc3VsdC50b29sYm94SWNvbiA9IHZhbHVlLnRvb2xib3hJY29uO1xyXG4gICAgICAgIHJlc3VsdC50b29sYm94TGFiZWwgPSB2YWx1ZS50b29sYm94TGFiZWw7XHJcbiAgICAgICAgcmVzdWx0LnRvb2xib3hEZXNjcmlwdGlvbiA9IHZhbHVlLnRvb2xib3hEZXNjcmlwdGlvbjtcclxuICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgfTtcclxuXHJcbiAgICBMYXlvdXRFZGl0b3IuQ29sdW1uLnRpbWVzID0gZnVuY3Rpb24gKHZhbHVlKSB7XHJcbiAgICAgICAgcmV0dXJuIF8udGltZXModmFsdWUsIGZ1bmN0aW9uIChuKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBMYXlvdXRFZGl0b3IuQ29sdW1uLmZyb20oe1xyXG4gICAgICAgICAgICAgICAgZGF0YTogbnVsbCxcclxuICAgICAgICAgICAgICAgIGh0bWxJZDogbnVsbCxcclxuICAgICAgICAgICAgICAgIGh0bWxDbGFzczogbnVsbCxcclxuICAgICAgICAgICAgICAgIGlzVGVtcGxhdGVkOiBmYWxzZSxcclxuICAgICAgICAgICAgICAgIHdpZHRoOiAxMiAvIHZhbHVlLFxyXG4gICAgICAgICAgICAgICAgb2Zmc2V0OiAwLFxyXG4gICAgICAgICAgICAgICAgY29sbGFwc2libGU6IG51bGwsXHJcbiAgICAgICAgICAgICAgICBjaGlsZHJlbjogW11cclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9O1xyXG59KShMYXlvdXRFZGl0b3IgfHwgKExheW91dEVkaXRvciA9IHt9KSk7IiwidmFyIExheW91dEVkaXRvcjtcclxuKGZ1bmN0aW9uIChMYXlvdXRFZGl0b3IpIHtcclxuXHJcbiAgICBMYXlvdXRFZGl0b3IuQ29udGVudCA9IGZ1bmN0aW9uIChkYXRhLCBodG1sSWQsIGh0bWxDbGFzcywgaHRtbFN0eWxlLCBpc1RlbXBsYXRlZCwgY29udGVudFR5cGUsIGNvbnRlbnRUeXBlTGFiZWwsIGNvbnRlbnRUeXBlQ2xhc3MsIGh0bWwsIGhhc0VkaXRvciwgcnVsZSkge1xyXG4gICAgICAgIExheW91dEVkaXRvci5FbGVtZW50LmNhbGwodGhpcywgXCJDb250ZW50XCIsIGRhdGEsIGh0bWxJZCwgaHRtbENsYXNzLCBodG1sU3R5bGUsIGlzVGVtcGxhdGVkLCBydWxlKTtcclxuXHJcbiAgICAgICAgdGhpcy5jb250ZW50VHlwZSA9IGNvbnRlbnRUeXBlO1xyXG4gICAgICAgIHRoaXMuY29udGVudFR5cGVMYWJlbCA9IGNvbnRlbnRUeXBlTGFiZWw7XHJcbiAgICAgICAgdGhpcy5jb250ZW50VHlwZUNsYXNzID0gY29udGVudFR5cGVDbGFzcztcclxuICAgICAgICB0aGlzLmh0bWwgPSBodG1sO1xyXG4gICAgICAgIHRoaXMuaGFzRWRpdG9yID0gaGFzRWRpdG9yO1xyXG5cclxuICAgICAgICB0aGlzLmdldElubmVyVGV4dCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgcmV0dXJuICQoJC5wYXJzZUhUTUwoXCI8ZGl2PlwiICsgdGhpcy5odG1sICsgXCI8L2Rpdj5cIikpLnRleHQoKTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICAvLyBUaGlzIGZ1bmN0aW9uIHdpbGwgYmUgb3ZlcndyaXR0ZW4gYnkgdGhlIENvbnRlbnQgZGlyZWN0aXZlLlxyXG4gICAgICAgIHRoaXMuc2V0SHRtbCA9IGZ1bmN0aW9uIChodG1sKSB7XHJcbiAgICAgICAgICAgIHRoaXMuaHRtbCA9IGh0bWw7XHJcbiAgICAgICAgICAgIHRoaXMuaHRtbFVuc2FmZSA9IGh0bWw7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB2YXIgYmFzZVRvT2JqZWN0ID0gdGhpcy50b09iamVjdDtcclxuICAgICAgICB0aGlzLnRvT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gYmFzZVRvT2JqZWN0KCk7XHJcbiAgICAgICAgICAgIHJlc3VsdC5jb250ZW50VHlwZUxhYmVsID0gdGhpcy5jb250ZW50VHlwZUxhYmVsO1xyXG4gICAgICAgICAgICByZXN1bHQuY29udGVudFR5cGVDbGFzcyA9IHRoaXMuY29udGVudFR5cGVDbGFzcztcclxuICAgICAgICAgICAgcmVzdWx0Lmh0bWwgPSB0aGlzLmh0bWw7XHJcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5zZXRIdG1sKGh0bWwpO1xyXG4gICAgfTtcclxuXHJcbiAgICBMYXlvdXRFZGl0b3IuQ29udGVudC5mcm9tID0gZnVuY3Rpb24gKHZhbHVlKSB7XHJcbiAgICAgICAgdmFyIHJlc3VsdCA9IG5ldyBMYXlvdXRFZGl0b3IuQ29udGVudChcclxuICAgICAgICAgICAgdmFsdWUuZGF0YSxcclxuICAgICAgICAgICAgdmFsdWUuaHRtbElkLFxyXG4gICAgICAgICAgICB2YWx1ZS5odG1sQ2xhc3MsXHJcbiAgICAgICAgICAgIHZhbHVlLmh0bWxTdHlsZSxcclxuICAgICAgICAgICAgdmFsdWUuaXNUZW1wbGF0ZWQsXHJcbiAgICAgICAgICAgIHZhbHVlLmNvbnRlbnRUeXBlLFxyXG4gICAgICAgICAgICB2YWx1ZS5jb250ZW50VHlwZUxhYmVsLFxyXG4gICAgICAgICAgICB2YWx1ZS5jb250ZW50VHlwZUNsYXNzLFxyXG4gICAgICAgICAgICB2YWx1ZS5odG1sLFxyXG4gICAgICAgICAgICB2YWx1ZS5oYXNFZGl0b3IsXHJcbiAgICAgICAgICAgIHZhbHVlLnJ1bGUpO1xyXG5cclxuICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgfTtcclxuXHJcbn0pKExheW91dEVkaXRvciB8fCAoTGF5b3V0RWRpdG9yID0ge30pKTsiXX0= diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/Models.min.js b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/Models.min.js index 33d6b753564..9b486b6647b 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/Models.min.js +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Scripts/Models.min.js @@ -1 +1 @@ -var LayoutEditor;!function(t){Array.prototype.move=function(t,i){this.splice(i,0,this.splice(t,1)[0])},t.childrenFrom=function(i){return _(i).map(function(i){return t.elementFrom(i)})};var i=t.registerFactory=function(i,n){var e=t.factories=t.factories||{};e[i]=n};i("Canvas",function(i){return t.Canvas.from(i)}),i("Grid",function(i){return t.Grid.from(i)}),i("Row",function(i){return t.Row.from(i)}),i("Column",function(i){return t.Column.from(i)}),i("Content",function(i){return t.Content.from(i)}),t.elementFrom=function(i){var n=t.factories[i.type];if(!n)throw new Error('No element with type "'+i.type+'" was found.');var e=n(i);return e},t.setModel=function(t,i){$(t).scope().element=i},t.getModel=function(t){return $(t).scope().element}}(LayoutEditor||(LayoutEditor={}));var LayoutEditor;!function(t){t.Editor=function(i,n){this.config=i,this.canvas=t.Canvas.from(n),this.initialState=JSON.stringify(this.canvas.toObject()),this.activeElement=null,this.focusedElement=null,this.dropTargetElement=null,this.isDragging=!1,this.isResizing=!1,this.recycleBin=new t.RecycleBin,this.resetToolboxElements=function(){this.toolboxElements=[t.Row.from({children:[]})]},this.isDirty=function(){var t=JSON.stringify(this.canvas.toObject());return this.initialState!=t},this.resetToolboxElements(),this.canvas.setEditor(this)}}(LayoutEditor||(LayoutEditor={}));var LayoutEditor;!function(t){t.RecycleBin=function(){this.elements=[],this.add=function(t){this.elements.push(t)},this.toObject=function(){for(var t={type:"RecycleBin",children:[]},i=0;i=0&&(this.children.splice(i,1),this.editor.recycleBin.add(t),t.getIsActive()&&(this.editor.activeElement=null),t.getIsFocused()&&(this.children.length>i?this.children[i].setIsFocused():i>0?this.children[i-1].setIsFocused():this.setIsFocused()))},this.moveFocusPrevChild=function(t){if(!(this.children.length<2)){var i=_(this.children).indexOf(t);i>0&&this.children[i-1].setIsFocused()}},this.moveFocusNextChild=function(t){if(!(this.children.length<2)){var i=_(this.children).indexOf(t);i0},this.canMoveChildDown=function(t){var i=_(this.children).indexOf(t);return i0?t.width<12:e<0&&t.width>1}if(0==t)return!0;var e=t;if(e<0){var o=12-a();e+=o,e>0&&(e=0)}for(;e<0&&_(d.children).any(function(t){return t.offset>0});)for(i=0;i0&&(s.offset--,e++)}for(;0!=e&&_(d.children).any(n);)for(i=0;i=0&&t.width>1},this.contractColumnRight=function(t,i){if(this.canContractColumnRight(t,i)){var n=_(this.children).indexOf(t);if(n>=0&&t.width>1&&(t.width--,this.children.length>n+1)){var e=this.children[n+1];i&&0==e.offset?e.width++:e.offset++}}},this.canExpandColumnRight=function(t,i){var n=_(this.children).indexOf(t);if(n>=0){if(t.width>=12)return!1;if(this.children.length>n+1){var e=this.children[n+1];return i&&0==e.offset?e.width>1:e.offset>0}return a()<12}return!1},this.expandColumnRight=function(t,i){if(this.canExpandColumnRight(t,i)){var n=_(this.children).indexOf(t);if(n>=0){if(this.children.length>n+1){var e=this.children[n+1];i&&0==e.offset?e.width--:e.offset--}t.width++}}},this.canExpandColumnLeft=function(t,i){var n=_(this.children).indexOf(t);if(n>=0){if(t.width>=12)return!1;if(n>0){var e=this.children[n-1];if(i&&0==t.offset)return e.width>1}return t.offset>0}return!1},this.expandColumnLeft=function(t,i){if(this.canExpandColumnLeft(t,i)){var n=_(this.children).indexOf(t);if(n>=0){if(n>0){var e=this.children[n-1];i&&0==t.offset?e.width--:t.offset--}else t.offset--;t.width++}}},this.canContractColumnLeft=function(t,i){var n=_(this.children).indexOf(t);return n>=0&&t.width>1},this.contractColumnLeft=function(t,i){if(this.canContractColumnLeft(t,i)){var n=_(this.children).indexOf(t);if(n>=0){if(n>0){var e=this.children[n-1];i&&0==t.offset?e.width++:t.offset++}else t.offset++;t.width--}}},this.evenColumns=function(){if(0!=this.children.length){var t=Math.floor(12/this.children.length);_(this.children).each(function(i){i.width=t,i.offset=0});var i=12%this.children.length;i>0&&c(i)}};var m=this.pasteChild;this.pasteChild=function(t){"Column"==t.type?this.beginAddColumn(t.width)&&(this.commitAddColumn(),m.call(this,t)):this.parent&&this.parent.pasteChild(t)},this.toObject=function(){var t=this.elementToObject();return t.children=this.childrenToObject(),t}},t.Row.from=function(i){var n=new t.Row(i.data,i.htmlId,i.htmlClass,i.htmlStyle,i.isTemplated,i.rule,t.childrenFrom(i.children));return n.toolboxIcon=i.toolboxIcon,n.toolboxLabel=i.toolboxLabel,n.toolboxDescription=i.toolboxDescription,n}}(LayoutEditor||(LayoutEditor={}));var LayoutEditor;!function(t){t.Column=function(i,n,e,o,s,h,r,l,a,c){t.Element.call(this,"Column",i,n,e,o,s,a),t.Container.call(this,["Grid","Content"],c),this.width=h,this.offset=r,this.collapsible=l;var d=!1,u=0,f=0;this.beginChange=function(){if(d)throw new Error("Column already has a pending change.");d=!0,u=this.width,f=this.offset},this.commitChange=function(){if(!d)throw new Error("Column has no pending change.");u=0,f=0,d=!1},this.rollbackChange=function(){if(!d)throw new Error("Column has no pending change.");this.width=u,this.offset=f,u=0,f=0,d=!1},this.canSplit=function(){return!this.isTemplated&&this.width>1},this.split=function(){if(this.canSplit()){var i=Math.floor(this.width/2),n=t.Column.from({data:null,htmlId:null,htmlClass:null,htmlStyle:null,width:i,offset:0,children:[]});this.width=this.width-i,this.parent.insertChild(n,this),n.setIsFocused()}},this.canContractRight=function(t){return!this.isTemplated&&this.parent.canContractColumnRight(this,t)},this.contractRight=function(t){this.canContractRight(t)&&this.parent.contractColumnRight(this,t)},this.canExpandRight=function(t){return!this.isTemplated&&this.parent.canExpandColumnRight(this,t)},this.expandRight=function(t){this.canExpandRight(t)&&this.parent.expandColumnRight(this,t)},this.canExpandLeft=function(t){return!this.isTemplated&&this.parent.canExpandColumnLeft(this,t)},this.expandLeft=function(t){this.canExpandLeft(t)&&this.parent.expandColumnLeft(this,t)},this.canContractLeft=function(t){return!this.isTemplated&&this.parent.canContractColumnLeft(this,t)},this.contractLeft=function(t){this.canContractLeft(t)&&this.parent.contractColumnLeft(this,t)},this.toObject=function(){var t=this.elementToObject();return t.width=this.width,t.offset=this.offset,t.collapsible=this.collapsible,t.children=this.childrenToObject(),t}},t.Column.from=function(i){var n=new t.Column(i.data,i.htmlId,i.htmlClass,i.htmlStyle,i.isTemplated,i.width,i.offset,i.collapsible,i.rule,t.childrenFrom(i.children));return n.toolboxIcon=i.toolboxIcon,n.toolboxLabel=i.toolboxLabel,n.toolboxDescription=i.toolboxDescription,n},t.Column.times=function(i){return _.times(i,function(n){return t.Column.from({data:null,htmlId:null,htmlClass:null,isTemplated:!1,width:12/i,offset:0,collapsible:null,children:[]})})}}(LayoutEditor||(LayoutEditor={}));var LayoutEditor;!function(t){t.Content=function(i,n,e,o,s,h,r,l,a,c,d){t.Element.call(this,"Content",i,n,e,o,s,d),this.contentType=h,this.contentTypeLabel=r,this.contentTypeClass=l,this.html=a,this.hasEditor=c,this.getInnerText=function(){return $($.parseHTML("
        "+this.html+"
        ")).text()},this.setHtml=function(t){this.html=t,this.htmlUnsafe=t};var u=this.toObject;this.toObject=function(){var t=u();return t.contentTypeLabel=this.contentTypeLabel,t.contentTypeClass=this.contentTypeClass,t.html=this.html,t},this.setHtml(a)},t.Content.from=function(i){var n=new t.Content(i.data,i.htmlId,i.htmlClass,i.htmlStyle,i.isTemplated,i.contentType,i.contentTypeLabel,i.contentTypeClass,i.html,i.hasEditor,i.rule);return n}}(LayoutEditor||(LayoutEditor={})); +var LayoutEditor;!function(t){Array.prototype.move=function(t,i){this.splice(i,0,this.splice(t,1)[0])},t.childrenFrom=function(i){return _(i).map(function(i){return t.elementFrom(i)})};var i=t.registerFactory=function(i,e){var n=t.factories=t.factories||{};n[i]=e};i("Canvas",function(i){return t.Canvas.from(i)}),i("Grid",function(i){return t.Grid.from(i)}),i("Row",function(i){return t.Row.from(i)}),i("Column",function(i){return t.Column.from(i)}),i("Content",function(i){return t.Content.from(i)}),t.elementFrom=function(i){var e=t.factories[i.type];if(!e)throw new Error('No element with type "'+i.type+'" was found.');var n=e(i);return n},t.setModel=function(t,i){$(t).scope().element=i},t.getModel=function(t){return $(t).scope().element}}(LayoutEditor||(LayoutEditor={}));var LayoutEditor;!function(t){t.Editor=function(i,e){this.config=i,this.canvas=t.Canvas.from(e),this.initialState=JSON.stringify(this.canvas.toObject()),this.activeElement=null,this.focusedElement=null,this.dropTargetElement=null,this.isDragging=!1,this.isResizing=!1,this.recycleBin=new t.RecycleBin,this.resetToolboxElements=function(){this.toolboxElements=[t.Row.from({children:[]})]},this.isDirty=function(){var t=JSON.stringify(this.canvas.toObject());return this.initialState!=t},this.resetToolboxElements(),this.canvas.setEditor(this)}}(LayoutEditor||(LayoutEditor={}));var LayoutEditor;!function(t){t.RecycleBin=function(){this.elements=[],this.add=function(t){this.elements.push(t)},this.toObject=function(){for(var t={type:"RecycleBin",children:[]},i=0;i=0&&(this.children.splice(i,1),this.editor.recycleBin.add(t),t.getIsActive()&&(this.editor.activeElement=null),t.getIsFocused()&&(this.children.length>i?this.children[i].setIsFocused():i>0?this.children[i-1].setIsFocused():this.setIsFocused()))},this.moveFocusPrevChild=function(t){if(!(this.children.length<2)){var i=_(this.children).indexOf(t);i>0&&this.children[i-1].setIsFocused()}},this.moveFocusNextChild=function(t){if(!(this.children.length<2)){var i=_(this.children).indexOf(t);i0},this.canMoveChildDown=function(t){var i=_(this.children).indexOf(t);return i0?t.width<12:n<0&&t.width>1}if(0==t)return!0;var n=t;if(n<0){var o=12-a();n+=o,n>0&&(n=0)}for(;n<0&&_(d.children).any(function(t){return t.offset>0});)for(i=0;i0&&(s.offset--,n++)}for(;0!=n&&_(d.children).any(e);)for(i=0;i=0&&t.width>1},this.contractColumnRight=function(t,i){if(this.canContractColumnRight(t,i)){var e=_(this.children).indexOf(t);if(e>=0&&t.width>1&&(t.width--,this.children.length>e+1)){var n=this.children[e+1];i&&0==n.offset?n.width++:n.offset++}}},this.canExpandColumnRight=function(t,i){var e=_(this.children).indexOf(t);if(e>=0){if(t.width>=12)return!1;if(this.children.length>e+1){var n=this.children[e+1];return i&&0==n.offset?n.width>1:n.offset>0}return a()<12}return!1},this.expandColumnRight=function(t,i){if(this.canExpandColumnRight(t,i)){var e=_(this.children).indexOf(t);if(e>=0){if(this.children.length>e+1){var n=this.children[e+1];i&&0==n.offset?n.width--:n.offset--}t.width++}}},this.canExpandColumnLeft=function(t,i){var e=_(this.children).indexOf(t);if(e>=0){if(t.width>=12)return!1;if(e>0){var n=this.children[e-1];if(i&&0==t.offset)return n.width>1}return t.offset>0}return!1},this.expandColumnLeft=function(t,i){if(this.canExpandColumnLeft(t,i)){var e=_(this.children).indexOf(t);if(e>=0){if(e>0){var n=this.children[e-1];i&&0==t.offset?n.width--:t.offset--}else t.offset--;t.width++}}},this.canContractColumnLeft=function(t,i){var e=_(this.children).indexOf(t);return e>=0&&t.width>1},this.contractColumnLeft=function(t,i){if(this.canContractColumnLeft(t,i)){var e=_(this.children).indexOf(t);if(e>=0){if(e>0){var n=this.children[e-1];i&&0==t.offset?n.width++:t.offset++}else t.offset++;t.width--}}},this.evenColumns=function(){if(0!=this.children.length){var t=Math.floor(12/this.children.length);_(this.children).each(function(i){i.width=t,i.offset=0});var i=12%this.children.length;i>0&&c(i)}};var m=this.pasteChild;this.pasteChild=function(t){"Column"==t.type?this.beginAddColumn(t.width)&&(this.commitAddColumn(),m.call(this,t)):this.parent&&this.parent.pasteChild(t)},this.toObject=function(){var t=this.elementToObject();return t.children=this.childrenToObject(),t}},t.Row.from=function(i){var e=new t.Row(i.data,i.htmlId,i.htmlClass,i.htmlStyle,i.isTemplated,i.rule,t.childrenFrom(i.children));return e.toolboxIcon=i.toolboxIcon,e.toolboxLabel=i.toolboxLabel,e.toolboxDescription=i.toolboxDescription,e}}(LayoutEditor||(LayoutEditor={}));var LayoutEditor;!function(t){t.Column=function(i,e,n,o,s,h,r,l,a,c){t.Element.call(this,"Column",i,e,n,o,s,a),t.Container.call(this,["Grid","Content"],c),this.width=h,this.offset=r,this.collapsible=l;var d=!1,u=0,f=0;this.beginChange=function(){if(d)throw new Error("Column already has a pending change.");d=!0,u=this.width,f=this.offset},this.commitChange=function(){if(!d)throw new Error("Column has no pending change.");u=0,f=0,d=!1},this.rollbackChange=function(){if(!d)throw new Error("Column has no pending change.");this.width=u,this.offset=f,u=0,f=0,d=!1},this.canSplit=function(){return!this.isTemplated&&this.width>1},this.split=function(){if(this.canSplit()){var i=Math.floor(this.width/2),e=t.Column.from({data:null,htmlId:null,htmlClass:null,htmlStyle:null,width:i,offset:0,children:[]});this.width=this.width-i,this.parent.insertChild(e,this),e.setIsFocused()}},this.canContractRight=function(t){return!this.isTemplated&&this.parent.canContractColumnRight(this,t)},this.contractRight=function(t){this.canContractRight(t)&&this.parent.contractColumnRight(this,t)},this.canExpandRight=function(t){return!this.isTemplated&&this.parent.canExpandColumnRight(this,t)},this.expandRight=function(t){this.canExpandRight(t)&&this.parent.expandColumnRight(this,t)},this.canExpandLeft=function(t){return!this.isTemplated&&this.parent.canExpandColumnLeft(this,t)},this.expandLeft=function(t){this.canExpandLeft(t)&&this.parent.expandColumnLeft(this,t)},this.canContractLeft=function(t){return!this.isTemplated&&this.parent.canContractColumnLeft(this,t)},this.contractLeft=function(t){this.canContractLeft(t)&&this.parent.contractColumnLeft(this,t)},this.toObject=function(){var t=this.elementToObject();return t.width=this.width,t.offset=this.offset,t.collapsible=this.collapsible,t.children=this.childrenToObject(),t}},t.Column.from=function(i){var e=new t.Column(i.data,i.htmlId,i.htmlClass,i.htmlStyle,i.isTemplated,i.width,i.offset,i.collapsible,i.rule,t.childrenFrom(i.children));return e.toolboxIcon=i.toolboxIcon,e.toolboxLabel=i.toolboxLabel,e.toolboxDescription=i.toolboxDescription,e},t.Column.times=function(i){return _.times(i,function(e){return t.Column.from({data:null,htmlId:null,htmlClass:null,isTemplated:!1,width:12/i,offset:0,collapsible:null,children:[]})})}}(LayoutEditor||(LayoutEditor={}));var LayoutEditor;!function(t){t.Content=function(i,e,n,o,s,h,r,l,a,c,d){t.Element.call(this,"Content",i,e,n,o,s,d),this.contentType=h,this.contentTypeLabel=r,this.contentTypeClass=l,this.html=a,this.hasEditor=c,this.getInnerText=function(){return $($.parseHTML("
        "+this.html+"
        ")).text()},this.setHtml=function(t){this.html=t,this.htmlUnsafe=t};var u=this.toObject;this.toObject=function(){var t=u();return t.contentTypeLabel=this.contentTypeLabel,t.contentTypeClass=this.contentTypeClass,t.html=this.html,t},this.setHtml(a)},t.Content.from=function(i){var e=new t.Content(i.data,i.htmlId,i.htmlClass,i.htmlStyle,i.isTemplated,i.contentType,i.contentTypeLabel,i.contentTypeClass,i.html,i.hasEditor,i.rule);return e}}(LayoutEditor||(LayoutEditor={})); diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Serialization/LocalizedStringYamlConverter.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Serialization/LocalizedStringYamlConverter.cs new file mode 100644 index 00000000000..b5779c293d8 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Serialization/LocalizedStringYamlConverter.cs @@ -0,0 +1,16 @@ +using System; +using Orchard.Localization; +using YamlDotNet.Core; +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; + +namespace Orchard.Layouts.Serialization { + public class LocalizedStringYamlConverter : IYamlTypeConverter { + public bool Accepts(Type type) => type == typeof(LocalizedString); + + public object ReadYaml(IParser parser, Type type) => new LocalizedString(parser.Consume()?.Value); + + public void WriteYaml(IEmitter emitter, object value, Type type) => + emitter.Emit(new Scalar((value as LocalizedString)?.Text ?? "")); + } +} diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ContentDisplayBase.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ContentDisplayBase.cs index 1e15899f74f..51f46b5d533 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ContentDisplayBase.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ContentDisplayBase.cs @@ -5,7 +5,9 @@ using Orchard.ContentManagement.Handlers; using Orchard.DisplayManagement; using Orchard.DisplayManagement.Descriptors; +using Orchard.Environment.Configuration; using Orchard.FileSystems.VirtualPath; +using Orchard.Mvc.Routes; using Orchard.UI.Zones; namespace Orchard.Layouts.Services { @@ -30,9 +32,9 @@ protected ContentDisplayBase( _requestContext = requestContext; _virtualPathProvider = virtualPathProvider; _workContextAccessor = workContextAccessor; - } + public abstract UrlPrefix TenantUrlPrefix { get; } public abstract string DefaultStereotype { get; } public BuildDisplayContext BuildDisplayContext(IContent content, string displayType, string groupId) { @@ -145,7 +147,12 @@ private void BindPlacement(BuildShapeContext context, string displayType, string /// Gets the current app-relative path, i.e. ~/my-blog/foo. /// private string GetPath() { - return VirtualPathUtility.AppendTrailingSlash(_virtualPathProvider.ToAppRelative(_requestContext.HttpContext.Request.Path)); + var appRelativePath = _virtualPathProvider.ToAppRelative(_requestContext.HttpContext.Request.Path); + // If the tenant has a prefix, we strip the tenant prefix away. + if (TenantUrlPrefix != null) + appRelativePath = TenantUrlPrefix.RemoveLeadingSegments(appRelativePath); + + return VirtualPathUtility.AppendTrailingSlash(appRelativePath); } } } diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ContentFieldDisplay.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ContentFieldDisplay.cs index a360722ac06..051051f8030 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ContentFieldDisplay.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ContentFieldDisplay.cs @@ -6,24 +6,39 @@ using Orchard.ContentManagement.Drivers; using Orchard.DisplayManagement; using Orchard.DisplayManagement.Descriptors; +using Orchard.Environment.Configuration; using Orchard.FileSystems.VirtualPath; +using Orchard.Mvc.Routes; namespace Orchard.Layouts.Services { public class ContentFieldDisplay : ContentDisplayBase, IContentFieldDisplay { private readonly IEnumerable _contentFieldDrivers; - + private readonly ShellSettings _shellSettings; public ContentFieldDisplay( IShapeFactory shapeFactory, - Lazy shapeTableLocator, + Lazy shapeTableLocator, RequestContext requestContext, IVirtualPathProvider virtualPathProvider, - IWorkContextAccessor workContextAccessor, - IEnumerable contentFieldDrivers) + IWorkContextAccessor workContextAccessor, + ShellSettings shellSettings, + IEnumerable contentFieldDrivers) : base(shapeFactory, shapeTableLocator, requestContext, virtualPathProvider, workContextAccessor) { - + _shellSettings = shellSettings; _contentFieldDrivers = contentFieldDrivers; } + public override UrlPrefix TenantUrlPrefix { + get { + if (!string.IsNullOrEmpty(_shellSettings.RequestUrlPrefix)) { + return new UrlPrefix(_shellSettings.RequestUrlPrefix); + } + else { + return null; + } + } + } + + public override string DefaultStereotype { get { return "ContentField"; } } @@ -63,7 +78,7 @@ public dynamic UpdateEditor(IContent content, ContentField field, IUpdateModel u if (result != null) result.Apply(context); }, Logger); - + return context.Shape; } diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ContentPartDisplay.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ContentPartDisplay.cs index bf44e122c51..8236fb33a38 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ContentPartDisplay.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ContentPartDisplay.cs @@ -6,23 +6,38 @@ using Orchard.ContentManagement.Drivers; using Orchard.DisplayManagement; using Orchard.DisplayManagement.Descriptors; +using Orchard.Environment.Configuration; using Orchard.FileSystems.VirtualPath; +using Orchard.Mvc.Routes; namespace Orchard.Layouts.Services { public class ContentPartDisplay : ContentDisplayBase, IContentPartDisplay { private readonly IEnumerable _contentPartDrivers; + private readonly ShellSettings _shellSettings; + public ContentPartDisplay( IShapeFactory shapeFactory, Lazy shapeTableLocator, RequestContext requestContext, IVirtualPathProvider virtualPathProvider, - IWorkContextAccessor workContextAccessor, + IWorkContextAccessor workContextAccessor, + ShellSettings shellSettings, IEnumerable contentPartDrivers) : base(shapeFactory, shapeTableLocator, requestContext, virtualPathProvider, workContextAccessor) { - + _shellSettings = shellSettings; _contentPartDrivers = contentPartDrivers; } + public override UrlPrefix TenantUrlPrefix { + get { + if (!string.IsNullOrEmpty(_shellSettings.RequestUrlPrefix)) { + return new UrlPrefix(_shellSettings.RequestUrlPrefix); + } + else { + return null; + } + } + } public override string DefaultStereotype { get { return "ContentPart"; } @@ -67,9 +82,8 @@ public dynamic UpdateEditor(ContentPart part, IUpdateModel updater, string group return context.Shape; } - private IEnumerable GetPartDrivers(string partName) { - return _contentPartDrivers.Where(x => GetPartOfDriver(x.GetType().BaseType).Name == partName); - } + private IEnumerable GetPartDrivers(string partName) => + _contentPartDrivers.Where(x => GetPartOfDriver(x.GetType()?.BaseType)?.Name == partName); private Type GetPartOfDriver(Type type) { var baseType = type; diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/DescribeElementsContext.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/DescribeElementsContext.cs index 3a7f18f7af8..42cb6fadfeb 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/DescribeElementsContext.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Services/DescribeElementsContext.cs @@ -4,6 +4,7 @@ namespace Orchard.Layouts.Services { public class DescribeElementsContext { public IContent Content { get; set; } public string CacheVaryParam { get; set; } + public bool IsHarvesting { get; set; } public static readonly DescribeElementsContext Empty = new DescribeElementsContext(); } diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementFilterProcessor.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementFilterProcessor.cs deleted file mode 100644 index 2dd58b24fea..00000000000 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementFilterProcessor.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; -using Orchard.Services; - -namespace Orchard.Layouts.Services { - public class ElementFilterProcessor : IElementFilterProcessor { - private readonly IEnumerable _filters; - public ElementFilterProcessor(IEnumerable filters) { - _filters = filters; - } - - public string ProcessContent(string text, string flavor, IDictionary context) { - foreach (var htmlFilter in _filters) { - var elementFilter = htmlFilter as IElementFilter; - text = elementFilter != null ? elementFilter.ProcessContent(text, flavor, context) : htmlFilter.ProcessContent(text, flavor); - } - return text; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementManager.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementManager.cs index 1281f5d85f2..5e01462504c 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementManager.cs @@ -40,7 +40,8 @@ public IEnumerable DescribeElements(DescribeElementsContext c var cacheKey = String.Format("LayoutElementTypes-{0}-{1}", contentType ?? "AnyType", context.CacheVaryParam); return _cacheManager.Get(cacheKey, true, acquireContext => { var harvesterContext = new HarvestElementsContext { - Content = context.Content + Content = context.Content, + IsHarvesting = context.IsHarvesting }; var query = from harvester in _elementHarvesters.Value diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementFilter.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementFilter.cs deleted file mode 100644 index 23d474c7359..00000000000 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementFilter.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Collections.Generic; -using Orchard.Services; - -namespace Orchard.Layouts.Services { - public interface IElementFilter : IHtmlFilter { - string ProcessContent(string text, string flavor, IDictionary context); - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementFilterProcessor.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementFilterProcessor.cs deleted file mode 100644 index f66dbf07a3d..00000000000 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementFilterProcessor.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Collections.Generic; -using Orchard.Services; - -namespace Orchard.Layouts.Services { - public interface IElementFilterProcessor : IDependency { - string ProcessContent(string text, string flavor, IDictionary context); - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ILayoutManager.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ILayoutManager.cs index 811bf38093e..116a42d4f3d 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ILayoutManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ILayoutManager.cs @@ -23,7 +23,7 @@ public interface ILayoutManager : IDependency { /// Renders the specified layout Data into a shape tree. /// /// The layout Data. - /// Optional. The dislay type to use when rendering the elements. + /// Optional. The display type to use when rendering the elements. /// Optional. Provides additional context to the elements being loaded and rendered. /// A shape representing the layout to be rendered. dynamic RenderLayout(string data, string displayType = null, IContent content = null); @@ -59,4 +59,4 @@ public interface ILayoutManager : IDependency { void Imported(ImportLayoutContext context); void ImportCompleted(ImportLayoutContext context); } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Styles/LayoutEditor.css b/src/Orchard.Web/Modules/Orchard.Layouts/Styles/LayoutEditor.css index 5d3c2a01394..510b925b3fb 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Styles/LayoutEditor.css +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Styles/LayoutEditor.css @@ -23,12 +23,11 @@ display: flex; margin-top: 1em; font-size: 14px; - -ms-flex-align: stretch; - align-items: stretch; } .layout-editor > .layout-canvas-wrapper { - -ms-flex-positive: 1; - flex-grow: 1; + -ms-flex: 1 1; + flex: 1 1; + height: fit-content; background-color: #f3f4f5; border: 1px solid #e4e5e6; } @@ -470,8 +469,7 @@ table[rules=all i] > tfoot > tr > td, table[rules=all i] > tfoot > tr > th { white-space: nowrap; font-size: 50%; font-variant-east-asian: ruby; - -webkit-text-emphasis: none; - text-emphasis: none; + text-emphasis: none; } .layout-editor .layout-content > .layout-element-wrapper .layout-content-markup rbc, .layout-editor .layout-html > .layout-element-wrapper .layout-content-markup rbc { @@ -990,33 +988,37 @@ table[rules=all i] > tfoot > tr > td, table[rules=all i] > tfoot > tr > th { height: auto; } +body .layout-toolbox-item { + border: 1px solid #e4e5e6; + background-color: #fff; + padding: 9px 12px; + cursor: default; + list-style-type: none; +} +body .layout-toolbox-item i { + display: inline-block; + width: 16px; + font: normal normal normal 14px/1 FontAwesome; +} +body .layout-toolbox-item + .layout-toolbox-item { + margin-top: 4px; +} .layout-editor > .layout-toolbox-wrapper { - position: relative; - margin-left: 12px; + position: sticky; + top: 1vh; + padding-left: 12px; width: 220px; - -ms-flex-negative: 0; - flex-shrink: 0; + overflow-y: auto; + scrollbar-width: thin; + min-height: 400px; + max-height: 98vh; + height: 100%; } .layout-editor > .layout-toolbox-wrapper > .layout-toolbox { border: 1px solid #e4e5e6; - width: 220px; - min-height: 400px; padding: 6px; background-color: #f3f4f5; } -.layout-editor > .layout-toolbox-wrapper > .layout-toolbox.sticky-top { - position: fixed; - top: 0; - max-height: 100%; - overflow-y: auto; -} -.layout-editor > .layout-toolbox-wrapper > .layout-toolbox.sticky-bottom { - position: absolute; - bottom: 0; -} -.layout-editor > .layout-toolbox-wrapper > .layout-toolbox .layout-toolbox-group { - margin-top: 12px; -} .layout-editor > .layout-toolbox-wrapper > .layout-toolbox .layout-toolbox-group .layout-toolbox-group-heading { display: block; margin-bottom: 4px; @@ -1108,4 +1110,4 @@ table[rules=all i] > tfoot > tr > td, table[rules=all i] > tfoot > tr > th { font-size: 0.9em; } -/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkVkaXRvci5sZXNzIiwiTGF5b3V0RWRpdG9yLmNzcyIsIkVsZW1lbnQubGVzcyIsIkNvbnRhaW5lci5sZXNzIiwiQ2FudmFzLmxlc3MiLCJSb3cubGVzcyIsIkNvbHVtbi5sZXNzIiwiQ29udGVudC5sZXNzIiwiUmVzZXQubGVzcyIsIlRvb2xib3gubGVzcyIsIlBvcHVwLmxlc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFFQTtFQUNJLHFCQUFBO0VBQUEsY0FBQTtFQUNBLHVCQUFBO01BQUEsK0JBQUE7RUFDQSxtQkFBQTtFQUNBLFVBQUE7Q0NESDtBREhEO0VBT1EscUJBQUE7RUFBQSxjQUFBO0NDRFA7QURORDtFQVVZLGtCQUFBO0NDRFg7QURNRDtFQUNJLHFCQUFBO0VBQUEsY0FBQTtFQUNBLGdCQUFBO0VBQ0EsZ0JBQUE7RUFDQSx3QkFBQTtNQUFBLHFCQUFBO0NDSkg7QURBRDtFQU9RLHFCQUFBO01BQUEsYUFBQTtFQUNBLDBCQUFBO0VBQ0EsMEJBQUE7Q0NKUDtBRExEO0VBWVksY0FBQTtFQUNBLG9CQUFBO0VBQ0EsaUJBQUE7Q0NKWDtBRFZEO0VBaUJnQix1QkFBQTtDQ0pmO0FEYkQ7RUFzQlksd0JBQUE7RUFDQSxxQkFBQTtFQUNBLG9CQUFBO0NDTlg7QURsQkQ7RUE2QlEsb0JBQUE7Q0NSUDtBRFlEO0VBQ0ksY0FBQTtDQ1ZIO0FEYU87O0VBQ0ksYUFBQTtFQUNBLGVBQUE7Q0NWWDtBRGFPO0VBQ0ksWUFBQTtDQ1hYO0FEQ0Q7O0VBY1ksZ0JBQUE7Q0NYWDtBREhEO0VBa0JZLHVCQUFBO0VBQ0EsWUFBQTtFQUNBLFdBQUE7Q0NaWDtBRGNXO0VBQ0ksb0JBQUE7RUFDQSxZQUFBO0NDWmY7QURaRDtFQTZCWSxnQkFBQTtDQ2RYO0FEZkQ7RUFrQ1EsbUJBQUE7RUFDQSwwQkFBQTtFQUNBLGlCQUFBO0VBQ0EsdUJBQUE7Q0NoQlA7QURyQkQ7RUF5Q1EscUJBQUE7RUFDQSxtQkFBQTtDQ2pCUDtBRHpCRDtFQThDUSxvQkFBQTtDQ2xC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MEJDO0NBQ0Y7QU1yVEQ7O0VDQVEsVUFBQTtFQUNBLFdBQUE7RUFDQSx3QkFBQTtDUHlUUDtBTTNURDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7RUNPUSxlQUFBO0NQc1ZQO0FNN1ZEOzs7Ozs7Ozs7Ozs7OztFQ1dRLGdCQUFBO0VBQ0EsbUJBQUE7Q1BrV1A7QU05V0Q7Ozs7RUNnQlEsa0JBQUE7RUFDQSxtQkFBQTtDUG9XUDtBTXJYRDs7RUNxQlEsbUJBQUE7Q1BvV1A7QU16WEQ7Ozs7Ozs7O0VDeUJRLHVCQUFBO0VBQ0EsaUJBQUE7Q1AwV1A7QU1wWUQ7Ozs7Ozs7Ozs7RUM4QlEsbUJBQUE7Q1BrWFA7QU1oWkQ7Ozs7RUNrQ1Esb0JBQUE7Q1BvWFA7QU10WkQ7Ozs7Ozs7O0VDc0NRLHVCQUFBO0NQMFhQO0FNaGFEOztFQzBDUSxrQkFBQTtDUDBYUDtBTXBhRDs7RUM4Q1EsbUJBQUE7Q1AwWFA7QU14YUQ7O0VDa0RRLG9CQUFBO0NQMFhQO0FNNWFEOztFQ3NEUSxzQkFBQTtDUDBYUDtBTWhiRDs7OztFQzBEUSxvQkFBQTtFQUNBLG1CQUFBO0NQNFhQO0FNdmJEOztFQ2dFUSxjQUFBO0NQMlhQO0FNM2JEOztFQ29FUSxtQkFBQTtFQUNBLG9CQUFBO0NQMlhQO0FNaGNEOztFQ3lFUSxtQkFBQTtFQUNBLG9CQUFBO0VBQ0EsZUFBQTtFQUNBLDhCQUFBO0VBQ0EsNEJBQUE7VUFBQSxvQkFBQTtDUDJYUDtBTXhjRDs7RUNpRlEsNkJBQUE7Q1AyWFA7QU01Y0Q7O0VDcUZRLDZCQUFBO0NQMlhQO0FNaGREOzs7Ozs7Ozs7O0VDeUZRLHNCQUFBO0NQbVlQO0FNNWREOztFQzhGUSxlQUFBO0NQa1lQO0FNaGVEOztFQ2tHUSxlQUFBO0NQa1lQO0FNcGVEOzs7O0VDc0dRLDJCQUFBO0NQb1lQO0FNMWVEOzs7Ozs7OztFQzJHUSxhQUFBO0NQeVlQO0FNcGZEOztFQytHUSxjQUFBO0NQeVlQO0FNeGZEOztFQ21IUSxtQkFBQTtFQUNBLGFBQUE7Q1B5WVA7QU03ZkQ7Ozs7RUN3SFEsa0NBQUE7Q1AyWVA7QU1uZ0JEOzs7O0VDNEhRLDJCQUFBO0NQNllQO0FNemdCRDs7Ozs7O0VDZ0lRLDhCQUFBO0NQaVpQO0FNamhCRDs7RUNvSVEsdUJBQUE7Q1BpWlA7QU1yaEJEOztFQ3dJUSxvQkFBQTtDUGlaUDtBTXpoQkQ7O0VDNElRLHFCQUFBO0NQaVpQO0FNN2hCRDs7RUNnSlEsY0FBQTtFQUNBLGlCQUFBO0NQaVpQO0FNbGlCRDs7RUNxSlEsb0JBQUE7Q1BpWlA7QU10aUJEOztFQ3lKUSxpQkFBQTtDUGlaUDtBTTFpQkQ7O0VDNkpRLG9CQUFBO0NQaVpQO0FNOWlCRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQ2lLUSxlQUFBO0NQcWFQO0FNdGtCRDs7RUNxS1EsbUJBQUE7RUFDQSxzQkFBQTtFQUNBLGtCQUFBO0VBQ0Esa0JBQUE7Q1BxYVA7QU03a0JEOztFQzRLUSxtQkFBQTtFQUNBLHNCQUFBO0VBQ0Esa0JBQUE7RUFDQSxrQkFBQTtDUHFhUDtBTXBsQkQ7O0VDbUxRLG1CQUFBO0VBQ0Esc0JBQUE7RUFDQSxrQkFBQTtFQUNBLGtCQUFBO0NQcWFQO0FNM2xCRDs7RUMwTFEsbUJBQUE7RUFDQSxzQkFBQTtFQUNBLGtCQUFBO0VBQ0Esa0JBQUE7Q1BxYVA7QU1sbUJEOztFQ2lNUSxtQkFBQTtFQUNBLHNCQUFBO0VBQ0Esa0JBQUE7RUFDQSxrQkFBQTtDUHFhUDtBTXptQkQ7O0VDd01RLG1CQUFBO0VBQ0Esc0JBQUE7RUFDQSxrQkFBQTtFQUNBLGtCQUFBO0NQcWFQO0FNaG5CRDs7Ozs7Ozs7Ozs7O0VDK01RLGVBQUE7Q1ArYVA7QU05bkJEOztFQ21OUSxtQkFBQTtDUCthUDtBTWxvQkQ7Ozs7Ozs7O0VDdU5RLGdCQUFBO0VBQ0EsbUJBQUE7Q1BxYlA7QU03b0JEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQytOWSxjQUFBO0VBQ0EsaUJBQUE7Q1BnZFg7QU1ockJEOztFQ29PUSxrQkFBQTtDUGdkUDtBTXByQkQ7Ozs7OztFQ3dPUSxtQkFBQTtDUG9kUDtBTTVyQkQ7O0VDNE9RLHlCQUFBO0NQb2RQO0FNaHNCRDs7OztFQ2dQUSxzQkFBQTtDUHNkUDtBTXRzQkQ7Ozs7Ozs7Ozs7OztFQ3NQWSx3QkFBQTtDUDhkWDtBTXB0QkQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQ2tRZ0Isd0JBQUE7Q1B3ZmY7QU0xdkJEOztFQ3NRUSxlQUFBO0NQd2ZQO0FNOXZCRDs7RUMwUVEsdUJBQUE7Q1B3ZlA7QU1sd0JEOzs7O0VDOFFRLDRCQUFBO0NQMGZQO0FNeHdCRDs7OztFQ2tSUSxzQkFBQTtDUDRmUDtBTTl3QkQ7Ozs7RUNzUlEsNEJBQUE7Q1A4ZlA7QU1weEJEOzs7O0VDMFJRLHlCQUFBO0NQZ2dCUDtBTTF4QkQ7Ozs7RUM4UlEsNEJBQUE7Q1BrZ0JQO0FNaHlCRDs7OztFQ2tTUSxtQkFBQTtDUG9nQlA7QU10eUJEOzs7Ozs7OztFQ3NTUSxvQkFBQTtDUDBnQlA7QU1oekJEOzs7Ozs7Ozs7Ozs7Ozs7O0VDMlNZLHFCQUFBO0NQdWhCWDtBTWwwQkQ7O0VDK1NRLHVCQUFBO0VBQ0Esb0JBQUE7RUFDQSwwQkFBQTtFQUNBLHFCQUFBO0NQdWhCUDtBTXowQkQ7Ozs7RUNzVFEsYUFBQTtDUHloQlA7QU0vMEJEOztFQzBUUSxrQkFBQTtDUHloQlA7QU1uMUJEOzs7Ozs7OztFQzhUUSx1QkFBQTtDUCtoQlA7QU03MUJEOzs7Ozs7RUNrVVEsd0JBQUE7Q1BtaUJQO0FNcjJCRDs7Ozs7O0VDc1VRLG1CQUFBO0NQdWlCUDtBTTcyQkQ7Ozs7Ozs7O0VDMFVRLHNCQUFBO0NQNmlCUDtBTXYzQkQ7Ozs7Ozs7Ozs7Ozs7O0VDd1dRLHFCQUFBO0NQK2hCUDtBTXY0QkQ7O0VDNFdRLHNCQUFBO0NQK2hCUDtBTTM0QkQ7Ozs7Ozs7Ozs7Ozs7O0VDaVhRLHVCQUFBO0NQMGlCUDtBTTM1QkQ7Ozs7RUNxWFEscUJBQUE7Q1A0aUJQO0FNajZCRDs7RUN5WFEsWUFBQTtFQUNBLG9CQUFBO0VBQ0Esa0JBQUE7RUFDQSxtQkFBQTtDUDRpQlA7QU14NkJEOztFQ2dZUSxpQkFBQTtFQUNBLGtCQUFBO0VBQ0EsOEJBQUE7RUFDQSwrQkFBQTtDUDRpQlA7QU0vNkJEOztFQ3VZUSxrQkFBQTtFQUNBLG1CQUFBO0NQNGlCUDtBTXA3QkQ7O0VBZW9CLHlCQUFBO0NOeTZCbkI7QU14N0JEOztFQW1Cb0IsNEJBQUE7Q055NkJuQjtBTXA2Qk87Ozs7RUFFUSxlQUFBO0VBQ0EsWUFBQTtFQUNBLGdCQUFBO0VBQ0EsYUFBQTtDTnc2QmY7QU1yOEJEOztFQW1DUSxlQUFBO0VBQ0EsWUFBQTtFQUNBLGdCQUFBO0VBQ0EsYUFBQTtDTnM2QlA7O0FRNzhCRDtFQUVRLG1CQUFBO0VBQ0Esa0JBQUE7RUFDQSxhQUFBO0VBQ0EscUJBQUE7TUFBQSxlQUFBO0NSKzhCUDtBUXA5QkQ7RUFRWSwwQkFBQTtFQUNBLGFBQUE7RUFDQSxrQkFBQTtFQUNBLGFBQUE7RUFDQSwwQkFBQTtDUis4Qlg7QVE3OEJXO0VBQ0ksZ0JBQUE7RUFDQSxPQUFBO0VBQ0EsaUJBQUE7RUFDQSxpQkFBQTtDUis4QmY7QVE1OEJXO0VBQ0ksbUJBQUE7RUFDQSxVQUFBO0NSODhCZjtBUXIrQkQ7RUEyQmdCLGlCQUFBO0NSNjhCZjtBUXgrQkQ7RUE4Qm9CLGVBQUE7RUFDQSxtQkFBQTtFQUNBLHNCQUFBO0NSNjhCbkI7QVEzOEJtQjtFQUNJLHNCQUFBO0VBQ0EsWUFBQTtFQUNBLGtCQUFBO0VBQ0EsOENBQUE7RUFDQSxtQkFBQTtFQUNBLGlCQUFBO0NSNjhCdkI7QVF6OEJlO0VBRVEsaUJBQUE7Q1IwOEJ2QjtBUTU4QmU7RUFNUSxjQUFBO0NSeThCdkI7QVEzL0JEO0VBdURvQixnQkFBQTtDUnU4Qm5CO0FROS9CRDtFQTJEb0IsMEJBQUE7RUFDQSx1QkFBQTtFQUNBLGtCQUFBO0VBQ0EsZ0JBQUE7Q1JzOEJuQjtBUXBnQ0Q7RUFpRXdCLHNCQUFBO0VBQ0EsWUFBQTtFQUNBLDhDQUFBO0NSczhCdkI7QVF6Z0NEO0VBdUV3QixnQkFBQTtDUnE4QnZCO0FRNWdDRDtFQTRFb0IsZ0JBQUE7Q1JtOEJuQjs7QVMvZ0NEO0VBRVEsY0FBQTtFQUNBLG1CQUFBO0VBQ0EsVUFBQTtFQUdBLGlEQUFBO0VBQ0EsMEJBQUE7RUFDQSxlQUFBO0VBQ0EsMEJBQUE7RUFDQSxpQkFBQTtFQUNBLFlBQUE7RUFDQSxlQUFBO0VBQ0EsaUJBQUE7RUFDQSxnQkFBQTtFQUNBLG9CQUFBO0VBQ0Esb0JBQUE7RUFDQSxpQkFBQTtDVGloQ1A7QVMvZ0NPO0VBQ0ksYUFBQTtDVGloQ1g7QVN0aUNEO0VBeUJZLHFCQUFBO0VBQUEsY0FBQTtFQUNBLGlCQUFBO0NUZ2hDWDtBUzFpQ0Q7RUE2QmdCLGlCQUFBO0VBQ0EsaURBQUE7RUFDQSxrQkFBQTtDVGdoQ2Y7QVMvaUNEO0VBb0NZLGlCQUFBO0NUOGdDWDtBU2xqQ0Q7RUF3Q1ksaUJBQUE7RUFDQSxrQkFBQTtFQUNBLGVBQUE7Q1Q2Z0NYO0FTdmpDRDtFQThDWSwwQkFBQTtFQUNBLGdCQUFBO0NUNGdDWDtBUzNqQ0Q7O0VBb0RnQixZQUFBO0NUMmdDZjtBUy9qQ0Q7RUF3RGdCLGVBQUE7RUFDQSxpQkFBQTtDVDBnQ2YiLCJmaWxlIjoiTGF5b3V0RWRpdG9yLmNzcyIsInNvdXJjZXNDb250ZW50IjpbIu+7v0BpbXBvcnQgXCJWYXJpYWJsZXMubGVzc1wiO1xyXG5cclxuLmxheW91dC1lZGl0b3ItdG9vbGJhciB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xyXG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xyXG4gICAgdG9wOiAxMHB4O1xyXG5cclxuICAgIC5sYXlvdXQtZWRpdG9yLXRvb2xiYXItZ3JvdXAge1xyXG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcblxyXG4gICAgICAgID4gbGkgKyBsaSB7XHJcbiAgICAgICAgICAgIG1hcmdpbi1sZWZ0OiAxMnB4O1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG5cclxuLmxheW91dC1lZGl0b3Ige1xyXG4gICAgZGlzcGxheTogZmxleDtcclxuICAgIG1hcmdpbi10b3A6IDFlbTtcclxuICAgIGZvbnQtc2l6ZTogQGZvbnQtc2l6ZTtcclxuICAgIGFsaWduLWl0ZW1zOiBzdHJldGNoO1xyXG5cclxuICAgID4gLmxheW91dC1jYW52YXMtd3JhcHBlciB7XHJcbiAgICAgICAgZmxleC1ncm93OiAxO1xyXG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6IEBncmF5LWJnO1xyXG4gICAgICAgIGJvcmRlcjogMXB4IHNvbGlkIEBncmF5LWJvcmRlcjtcclxuXHJcbiAgICAgICAgPiAubGF5b3V0LXRvb2xiYXItY29udGFpbmVyIHtcclxuICAgICAgICAgICAgZGlzcGxheTogbm9uZTtcclxuICAgICAgICAgICAgbWFyZ2luOiBAY29udGFpbmVyLXBhZGRpbmcgQGNvbnRhaW5lci1wYWRkaW5nIDA7XHJcbiAgICAgICAgICAgIG1pbi1oZWlnaHQ6IDcxcHg7XHJcblxyXG4gICAgICAgICAgICA+IC5tY2UtcGFuZWwge1xyXG4gICAgICAgICAgICAgICAgd2lkdGg6IDEwMCUgIWltcG9ydGFudDtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCA+IC5sYXlvdXQtcGxhY2Vob2xkZXIge1xyXG4gICAgICAgICAgICBib3JkZXI6IDFweCBkYXNoZWQgI2NjYztcclxuICAgICAgICAgICAgcGFkZGluZzogMC4yZW0gMC40ZW07XHJcbiAgICAgICAgICAgIGJhY2tncm91bmQ6ICNlOGU4ZTg7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC5sYXlvdXQtc25pcHBldCB7XHJcbiAgICAgICAgYmFja2dyb3VuZDogI2U4ZThlODtcclxuICAgIH1cclxufVxyXG5cclxuLmxheW91dC1lZGl0b3ItaGVscC1kaWFsb2cge1xyXG4gICAgZGlzcGxheTogbm9uZTtcclxuXHJcbiAgICAuaGVscC1yb3cge1xyXG4gICAgICAgICY6YmVmb3JlLCAmOmFmdGVyIHtcclxuICAgICAgICAgICAgY29udGVudDogXCIgXCI7IC8vIDFcclxuICAgICAgICAgICAgZGlzcGxheTogdGFibGU7IC8vIDJcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICY6YWZ0ZXIge1xyXG4gICAgICAgICAgICBjbGVhcjogYm90aDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgID4gLmhlbHAtY29sdW1uLWZ1bGwsID4gLmhlbHAtY29sdW1uLWhhbGYge1xyXG4gICAgICAgICAgICBtYXJnaW46IDAuNWVtIDA7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICA+IC5oZWxwLWNvbHVtbi1oYWxmIHtcclxuICAgICAgICAgICAgYm94LXNpemluZzogYm9yZGVyLWJveDtcclxuICAgICAgICAgICAgZmxvYXQ6IGxlZnQ7XHJcbiAgICAgICAgICAgIHdpZHRoOiA1MCU7XHJcblxyXG4gICAgICAgICAgICAmOm50aC1jaGlsZCgybikge1xyXG4gICAgICAgICAgICAgICAgcGFkZGluZy1yaWdodDogMTBweDtcclxuICAgICAgICAgICAgICAgIGNsZWFyOiBsZWZ0O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICArIC5oZWxwLXJvdyB7XHJcbiAgICAgICAgICAgIG1hcmdpbi10b3A6IDFlbTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgY29kZSB7XHJcbiAgICAgICAgYm9yZGVyLXJhZGl1czogNHB4O1xyXG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6ICNmM2Y0ZjU7XHJcbiAgICAgICAgcGFkZGluZzogMnB4IDRweDtcclxuICAgICAgICBmb250LWZhbWlseTogbW9ub3NwYWNlO1xyXG4gICAgfVxyXG5cclxuICAgIHAge1xyXG4gICAgICAgIG1hcmdpbi1ib3R0b206IDAuNWVtO1xyXG4gICAgICAgIGxpbmUtaGVpZ2h0OiAxLjZlbTtcclxuICAgIH1cclxuXHJcbiAgICB0YWJsZSA+IHRib2R5ID4gdHIgPiB0ZDpmaXJzdC1jaGlsZCB7XHJcbiAgICAgICAgcGFkZGluZy1yaWdodDogMTBweDtcclxuICAgIH1cclxufVxyXG4iLCIubGF5b3V0LWVkaXRvci10b29sYmFyIHtcbiAgZGlzcGxheTogZmxleDtcbiAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIHRvcDogMTBweDtcbn1cbi5sYXlvdXQtZWRpdG9yLXRvb2xiYXIgLmxheW91dC1lZGl0b3ItdG9vbGJhci1ncm91cCB7XG4gIGRpc3BsYXk6IGZsZXg7XG59XG4ubGF5b3V0LWVkaXRvci10b29sYmFyIC5sYXlvdXQtZWRpdG9yLXRvb2xiYXItZ3JvdXAgPiBsaSArIGxpIHtcbiAgbWFyZ2luLWxlZnQ6IDEycHg7XG59XG4ubGF5b3V0LWVkaXRvciB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIG1hcmdpbi10b3A6IDFlbTtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBhbGlnbi1pdGVtczogc3RyZXRjaDtcbn1cbi5sYXlvdXQtZWRpdG9yID4gLmxheW91dC1jYW52YXMtd3JhcHBlciB7XG4gIGZsZXgtZ3JvdzogMTtcbiAgYmFja2dyb3VuZC1jb2xvcjogI2YzZjRmNTtcbiAgYm9yZGVyOiAxcHggc29saWQgI2U0ZTVlNjtcbn1cbi5sYXlvdXQtZWRpdG9yID4gLmxheW91dC1jYW52YXMtd3JhcHBlciA+IC5sYXlvdXQtdG9vbGJhci1jb250YWluZXIge1xuICBkaXNwbGF5OiBub25lO1xuICBtYXJnaW46IDEycHggMTJweCAwO1xuICBtaW4taGVpZ2h0OiA3MXB4O1xufVxuLmxheW91dC1lZGl0b3IgPiAubGF5b3V0LWNhbnZhcy13cmFwcGVyID4gLmxheW91dC10b29sYmFyLWNvbnRhaW5lciA+IC5tY2UtcGFuZWwge1xuICB3aWR0aDogMTAwJSAhaW1wb3J0YW50O1xufVxuLmxheW91dC1lZGl0b3IgPiAubGF5b3V0LWNhbnZhcy13cmFwcGVyIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgPiAubGF5b3V0LXBsYWNlaG9sZGVyIHtcbiAgYm9yZGVyOiAxcHggZGFzaGVkICNjY2M7XG4gIHBhZGRpbmc6IDAuMmVtIDAuNGVtO1xuICBiYWNrZ3JvdW5kOiAjZThlOGU4O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1zbmlwcGV0IHtcbiAgYmFja2dyb3VuZDogI2U4ZThlODtcbn1cbi5sYXlvdXQtZWRpdG9yLWhlbHAtZGlhbG9nIHtcbiAgZGlzcGxheTogbm9uZTtcbn1cbi5sYXlvdXQtZWRpdG9yLWhlbHAtZGlhbG9nIC5oZWxwLXJvdzpiZWZvcmUsXG4ubGF5b3V0LWVkaXRvci1oZWxwLWRpYWxvZyAuaGVscC1yb3c6YWZ0ZXIge1xuICBjb250ZW50OiBcIiBcIjtcbiAgZGlzcGxheTogdGFibGU7XG59XG4ubGF5b3V0LWVkaXRvci1oZWxwLWRpYWxvZyAuaGVscC1yb3c6YWZ0ZXIge1xuICBjbGVhcjogYm90aDtcbn1cbi5sYXlvdXQtZWRpdG9yLWhlbHAtZGlhbG9nIC5oZWxwLXJvdyA+IC5oZWxwLWNvbHVtbi1mdWxsLFxuLmxheW91dC1lZGl0b3ItaGVscC1kaWFsb2cgLmhlbHAtcm93ID4gLmhlbHAtY29sdW1uLWhhbGYge1xuICBtYXJnaW46IDAuNWVtIDA7XG59XG4ubGF5b3V0LWVkaXRvci1oZWxwLWRpYWxvZyAuaGVscC1yb3cgPiAuaGVscC1jb2x1bW4taGFsZiB7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gIGZsb2F0OiBsZWZ0O1xuICB3aWR0aDogNTAlO1xufVxuLmxheW91dC1lZGl0b3ItaGVscC1kaWFsb2cgLmhlbHAtcm93ID4gLmhlbHAtY29sdW1uLWhhbGY6bnRoLWNoaWxkKDJuKSB7XG4gIHBhZGRpbmctcmlnaHQ6IDEwcHg7XG4gIGNsZWFyOiBsZWZ0O1xufVxuLmxheW91dC1lZGl0b3ItaGVscC1kaWFsb2cgLmhlbHAtcm93ICsgLmhlbHAtcm93IHtcbiAgbWFyZ2luLXRvcDogMWVtO1xufVxuLmxheW91dC1lZGl0b3ItaGVscC1kaWFsb2cgY29kZSB7XG4gIGJvcmRlci1yYWRpdXM6IDRweDtcbiAgYmFja2dyb3VuZC1jb2xvcjogI2YzZjRmNTtcbiAgcGFkZGluZzogMnB4IDRweDtcbiAgZm9udC1mYW1pbHk6IG1vbm9zcGFjZTtcbn1cbi5sYXlvdXQtZWRpdG9yLWhlbHAtZGlhbG9nIHAge1xuICBtYXJnaW4tYm90dG9tOiAwLjVlbTtcbiAgbGluZS1oZWlnaHQ6IDEuNmVtO1xufVxuLmxheW91dC1lZGl0b3ItaGVscC1kaWFsb2cgdGFibGUgPiB0Ym9keSA+IHRyID4gdGQ6Zmlyc3QtY2hpbGQge1xuICBwYWRkaW5nLXJpZ2h0OiAxMHB4O1xufVxuXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWVsZW1lbnQge1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIG1hcmdpbi10b3A6IDA7XG4gIG1hcmdpbi1yaWdodDogMDtcbiAgbWFyZ2luLWJvdHRvbTogMDtcbiAgcGFkZGluZzogMDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtZWxlbWVudDpub3QoLmxheW91dC1jb2x1bW4pIHtcbiAgbWFyZ2luLWxlZnQ6IDA7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWVsZW1lbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtcGFuZWwge1xuICBkaXNwbGF5OiBub25lO1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIG1hcmdpbjogMDtcbiAgei1pbmRleDogMjA7XG4gIGhlaWdodDogMjVweDtcbiAgcGFkZGluZzogMCA2cHg7XG4gIGxpc3Qtc3R5bGU6IG5vbmU7XG4gIHdoaXRlLXNwYWNlOiBub3dyYXA7XG4gIGxpbmUtaGVpZ2h0OiAyNXB4O1xuICB2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1lbGVtZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LXBhbmVsID4gLmxheW91dC1wYW5lbC1pdGVtIHtcbiAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICBoZWlnaHQ6IDI1cHg7XG4gIHBhZGRpbmc6IDFweCA2cHggMDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtZWxlbWVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1wYW5lbCA+IC5sYXlvdXQtcGFuZWwtbGFiZWwge1xuICBmb250LXNpemU6IDEzcHg7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWVsZW1lbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtcGFuZWwgPiAubGF5b3V0LXBhbmVsLWFjdGlvbiB7XG4gIGRpc3BsYXk6IG5vbmU7XG4gIHdpZHRoOiAyOHB4O1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIHRleHQtYWxpZ246IGNlbnRlcjtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtZWxlbWVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1wYW5lbC1tYWluIHtcbiAgdG9wOiAtMjdweDtcbiAgbGVmdDogLTJweDtcbn1cbi5sYXlvdXQtZWRpdG9yIGxpLmxheW91dC1lbGVtZW50IHtcbiAgbGlzdC1zdHlsZTogbm9uZTtcbn1cbi5sYXlvdXQtZWRpdG9yOm5vdCgubGF5b3V0LWVkaXRvci1kcmFnZ2luZykgLmxheW91dC1lbGVtZW50LWFjdGl2ZSxcbi5sYXlvdXQtZWRpdG9yOm5vdCgubGF5b3V0LWVkaXRvci1kcmFnZ2luZykgLmxheW91dC1lbGVtZW50LWZvY3VzZWQge1xuICBib3JkZXItd2lkdGg6IDJweDtcbiAgYm9yZGVyLXN0eWxlOiBzb2xpZDtcbn1cbi5sYXlvdXQtZWRpdG9yOm5vdCgubGF5b3V0LWVkaXRvci1kcmFnZ2luZykgLmxheW91dC1lbGVtZW50LWFjdGl2ZSA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyLFxuLmxheW91dC1lZGl0b3I6bm90KC5sYXlvdXQtZWRpdG9yLWRyYWdnaW5nKSAubGF5b3V0LWVsZW1lbnQtZm9jdXNlZCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIHtcbiAgbWFyZ2luOiAtMnB4O1xufVxuLmxheW91dC1lZGl0b3I6bm90KC5sYXlvdXQtZWRpdG9yLWRyYWdnaW5nKSAubGF5b3V0LWVsZW1lbnQtYWN0aXZlIHtcbiAgYm9yZGVyLWNvbG9yOiByZ2JhKDEwNCwgMTA0LCAxMDQsIDAuMSk7XG59XG4ubGF5b3V0LWVkaXRvcjpub3QoLmxheW91dC1lZGl0b3ItZHJhZ2dpbmcpIC5sYXlvdXQtZWxlbWVudC1hY3RpdmUgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtcGFuZWwtbWFpbiB7XG4gIGRpc3BsYXk6IGJsb2NrO1xuICB6LWluZGV4OiAzMDtcbiAgYmFja2dyb3VuZC1jb2xvcjogcmdiYSgxMDQsIDEwNCwgMTA0LCAwLjEpO1xufVxuLmxheW91dC1lZGl0b3I6bm90KC5sYXlvdXQtZWRpdG9yLWRyYWdnaW5nKSAubGF5b3V0LWVsZW1lbnQtZm9jdXNlZCB7XG4gIGJvcmRlci1jb2xvcjogIzY0ODcyMTtcbn1cbi5sYXlvdXQtZWRpdG9yOm5vdCgubGF5b3V0LWVkaXRvci1kcmFnZ2luZykgLmxheW91dC1lbGVtZW50LWZvY3VzZWQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtcGFuZWwge1xuICBkaXNwbGF5OiBibG9jaztcbiAgYmFja2dyb3VuZC1jb2xvcjogIzY0ODcyMTtcbiAgY29sb3I6ICNmZWZlZmU7XG59XG4ubGF5b3V0LWVkaXRvcjpub3QoLmxheW91dC1lZGl0b3ItZHJhZ2dpbmcpIC5sYXlvdXQtZWxlbWVudC1mb2N1c2VkID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LXBhbmVsID4gLmxheW91dC1wYW5lbC1hY3Rpb24ge1xuICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG59XG4ubGF5b3V0LWVkaXRvcjpub3QoLmxheW91dC1lZGl0b3ItZHJhZ2dpbmcpIC5sYXlvdXQtZWxlbWVudC1mb2N1c2VkID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LXBhbmVsID4gLmxheW91dC1wYW5lbC1hY3Rpb246aG92ZXIge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiAjODJiMDJiO1xufVxuLmxheW91dC1lZGl0b3I6bm90KC5sYXlvdXQtZWRpdG9yLWRyYWdnaW5nKSAubGF5b3V0LWVsZW1lbnQtZm9jdXNlZCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1wYW5lbCA+IC5sYXlvdXQtcGFuZWwtYWN0aW9uLmRpc2FibGVkIHtcbiAgY3Vyc29yOiBkZWZhdWx0O1xuICBjb2xvcjogcmdiYSgyNTQsIDI1NCwgMjU0LCAwLjQpO1xufVxuLmxheW91dC1lZGl0b3I6bm90KC5sYXlvdXQtZWRpdG9yLWRyYWdnaW5nKSAubGF5b3V0LWVsZW1lbnQtZm9jdXNlZCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1wYW5lbCA+IC5sYXlvdXQtcGFuZWwtYWN0aW9uLmRpc2FibGVkOmhvdmVyIHtcbiAgYmFja2dyb3VuZC1jb2xvcjogIzY0ODcyMTtcbn1cbi5sYXlvdXQtZWRpdG9yOm5vdCgubGF5b3V0LWVkaXRvci1kcmFnZ2luZykgLmxheW91dC1lbGVtZW50LWZvY3VzZWQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtcGFuZWwgPiAubGF5b3V0LXBhbmVsLWFjdGlvbi5hY3RpdmUge1xuICBjb2xvcjogI2RlZmY0MjtcbiAgYmFja2dyb3VuZC1jb2xvcjogIzczOWIyNjtcbn1cbi5sYXlvdXQtZWRpdG9yOm5vdCgubGF5b3V0LWVkaXRvci1kcmFnZ2luZykgLmxheW91dC1lbGVtZW50LWZvY3VzZWQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtcGFuZWwgPiAubGF5b3V0LXBhbmVsLWFjdGlvbi5hY3RpdmU6aG92ZXIge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiAjODJiMDJiO1xufVxuLmxheW91dC1lZGl0b3I6bm90KC5sYXlvdXQtZWRpdG9yLWRyYWdnaW5nKSAubGF5b3V0LWVsZW1lbnQtc2VsZWN0ZWQge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDEwMCwgMTM1LCAzMywgMC4wOCk7XG59XG4ubGF5b3V0LWVkaXRvciAudWktc29ydGFibGUtcGxhY2Vob2xkZXIge1xuICBkaXNwbGF5OiBub25lO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1lbGVtZW50LWRyb3B0YXJnZXQge1xuICBib3gtc2hhZG93OiBpbnNldCAwIDAgMTJweCA2cHggcmdiYSgxMDAsIDEzNSwgMzMsIDAuNSk7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWVsZW1lbnQtZHJvcHRhcmdldCAudWktc29ydGFibGUtcGxhY2Vob2xkZXIge1xuICBkaXNwbGF5OiBibG9jaztcbiAgdmlzaWJpbGl0eTogdmlzaWJsZSAhaW1wb3J0YW50O1xuICBtaW4taGVpZ2h0OiA3OHB4O1xuICBib3JkZXI6IDJweCBkYXNoZWQgIzY0ODcyMSAhaW1wb3J0YW50O1xuICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDEwMCwgMTM1LCAzMywgMC4xNik7XG59XG4ubGF5b3V0LWVkaXRvciAubWVkaWEtdGh1bWJuYWlsIGltZyB7XG4gIG1heC13aWR0aDogMTAwJTtcbiAgbWF4LWhlaWdodDogMTAwJTtcbn1cblxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250YWluZXIgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY29udGFpbmVyLWNoaWxkcmVuLXBsYWNlaG9sZGVyIHtcbiAgZGlzcGxheTogbm9uZTtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgbWFyZ2luOiAxMXB4O1xuICBtaW4taGVpZ2h0OiA4MHB4O1xuICBib3JkZXI6IDFweCBkYXNoZWQgcmdiYSgxMjQsIDEyNCwgMTI0LCAwLjQpO1xuICBib3JkZXItcmFkaXVzOiA0cHg7XG4gIHBhZGRpbmc6IDEycHg7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICBmb250LXNpemU6IDEzcHg7XG4gIGZvbnQtc3R5bGU6IGl0YWxpYztcbiAgb3BhY2l0eTogMC42O1xuICB0ZXh0LWFsaWduOiBjZW50ZXI7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRhaW5lciA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1jaGlsZHJlbiB7XG4gIHBhZGRpbmc6IDEycHg7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRhaW5lciA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1jaGlsZHJlbiA+IC5sYXlvdXQtZWxlbWVudDpub3QoLmxheW91dC1jb250YWluZXIpICsgLmxheW91dC1lbGVtZW50Om5vdCgubGF5b3V0LWNvbnRhaW5lcikge1xuICBtYXJnaW4tdG9wOiAxMnB4O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250YWluZXIgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY2hpbGRyZW4gPiAudWktc29ydGFibGUtaGVscGVyOmZpcnN0LWNoaWxkICsgLmxheW91dC1lbGVtZW50Om5vdCgubGF5b3V0LWNvbnRhaW5lcikge1xuICBtYXJnaW4tdG9wOiAwO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250YWluZXIgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlci5sYXlvdXQtY29udGFpbmVyLWVtcHR5ID4gLmxheW91dC1jb250YWluZXItY2hpbGRyZW4tcGxhY2Vob2xkZXIge1xuICBkaXNwbGF5OiBmbGV4O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250YWluZXIgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlci5sYXlvdXQtY29udGFpbmVyLWVtcHR5ID4gLmxheW91dC1jaGlsZHJlbiB7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgdG9wOiAwO1xuICByaWdodDogMDtcbiAgYm90dG9tOiAwO1xuICBsZWZ0OiAwO1xufVxuLmxheW91dC1lZGl0b3I6bm90KC5sYXlvdXQtZWRpdG9yLWRyYWdnaW5nKSAubGF5b3V0LWNvbnRhaW5lci5sYXlvdXQtZWxlbWVudC1mb2N1c2VkID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNoaWxkcmVuID4gLmxheW91dC1lbGVtZW50Om5vdCgubGF5b3V0LWVsZW1lbnQtYWN0aXZlKSB7XG4gIGJvcmRlcjogMXB4IGRhc2hlZCByZ2JhKDEyNCwgMTI0LCAxMjQsIDAuNik7XG59XG4ubGF5b3V0LWVkaXRvcjpub3QoLmxheW91dC1lZGl0b3ItZHJhZ2dpbmcpIC5sYXlvdXQtY29udGFpbmVyLmxheW91dC1lbGVtZW50LWZvY3VzZWQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY2hpbGRyZW4gPiAubGF5b3V0LWVsZW1lbnQ6bm90KC5sYXlvdXQtZWxlbWVudC1hY3RpdmUpID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIge1xuICBtYXJnaW46IC0xcHg7XG59XG4ubGF5b3V0LWVkaXRvcjpub3QoLmxheW91dC1lZGl0b3ItZHJhZ2dpbmcpIC5sYXlvdXQtY29udGFpbmVyLmxheW91dC1lbGVtZW50LWZvY3VzZWQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY2hpbGRyZW4gPiAubGF5b3V0LWNvbnRhaW5lciArIC5sYXlvdXQtY29udGFpbmVyOm5vdCgubGF5b3V0LWVsZW1lbnQtYWN0aXZlKSB7XG4gIGJvcmRlci10b3A6IDA7XG59XG4ubGF5b3V0LWVkaXRvcjpub3QoLmxheW91dC1lZGl0b3ItZHJhZ2dpbmcpIC5sYXlvdXQtY29udGFpbmVyLmxheW91dC1lbGVtZW50LWZvY3VzZWQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY2hpbGRyZW4gPiAubGF5b3V0LWNvbnRhaW5lciArIC5sYXlvdXQtY29udGFpbmVyOm5vdCgubGF5b3V0LWVsZW1lbnQtYWN0aXZlKSA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIHtcbiAgbWFyZ2luLXRvcDogMDtcbn1cblxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jYW52YXMgI2R1bW15IHtcbiAgZGlzcGxheTogbm9uZTtcbn1cblxuLmxheW91dC1lZGl0b3IgLmxheW91dC1yb3cubGF5b3V0LWVsZW1lbnQtZm9jdXNlZDpub3QoLmxheW91dC1lbGVtZW50LWRyb3B0YXJnZXQpID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNoaWxkcmVuID4gLmxheW91dC1lbGVtZW50Om5vdCgubGF5b3V0LWVsZW1lbnQtYWN0aXZlKSB7XG4gIGJvcmRlci10b3A6IDFweCBkYXNoZWQgcmdiYSgxMjQsIDEyNCwgMTI0LCAwLjYpICFpbXBvcnRhbnQ7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LXJvdy5sYXlvdXQtZWxlbWVudC1mb2N1c2VkOm5vdCgubGF5b3V0LWVsZW1lbnQtZHJvcHRhcmdldCkgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY2hpbGRyZW4gPiAubGF5b3V0LWVsZW1lbnQ6bm90KC5sYXlvdXQtZWxlbWVudC1hY3RpdmUpID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIge1xuICBtYXJnaW4tdG9wOiAtMXB4ICFpbXBvcnRhbnQ7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LXJvdy5sYXlvdXQtZWxlbWVudC1mb2N1c2VkOm5vdCgubGF5b3V0LWVsZW1lbnQtZHJvcHRhcmdldCkgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY2hpbGRyZW4gPiAubGF5b3V0LWVsZW1lbnQgKyAubGF5b3V0LWVsZW1lbnQ6bm90KC5sYXlvdXQtZWxlbWVudC1hY3RpdmUpIHtcbiAgYm9yZGVyLWxlZnQ6IDAgIWltcG9ydGFudDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtcm93LmxheW91dC1lbGVtZW50LWZvY3VzZWQ6bm90KC5sYXlvdXQtZWxlbWVudC1kcm9wdGFyZ2V0KSA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1jaGlsZHJlbiA+IC5sYXlvdXQtZWxlbWVudCArIC5sYXlvdXQtZWxlbWVudDpub3QoLmxheW91dC1lbGVtZW50LWFjdGl2ZSkgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciB7XG4gIG1hcmdpbi1sZWZ0OiAwICFpbXBvcnRhbnQ7XG59XG5cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29sdW1uID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNvbHVtbi1yZXNpemUtYmFyIHtcbiAgZGlzcGxheTogbm9uZTtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICB6LWluZGV4OiAzMDtcbiAgdG9wOiAwO1xuICB3aWR0aDogMTZweDtcbiAgaGVpZ2h0OiAxMDAlO1xuICBjdXJzb3I6IGNvbC1yZXNpemU7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbHVtbiA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1jb2x1bW4tcmVzaXplLWJhci1sZWZ0IHtcbiAgbGVmdDogLTZweDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29sdW1uID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNvbHVtbi1yZXNpemUtYmFyLXJpZ2h0IHtcbiAgcmlnaHQ6IC02cHg7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbHVtbi5sYXlvdXQtZWxlbWVudC1mb2N1c2VkID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNvbHVtbi1yZXNpemUtYmFyIHtcbiAgZGlzcGxheTogYmxvY2s7XG59XG5cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCB7XG4gIG1pbi1oZWlnaHQ6IDFlbTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHtcbiAgcGFkZGluZzogMnB4O1xuICBvdmVyZmxvdy14OiBoaWRkZW47XG4gIGxpbmUtaGVpZ2h0OiBub3JtYWw7XG4gIC8qIHRoaXMgY29sb3IgaXMganVzdCBhIHN1Z2dlc3Rpb24gYW5kIGNhbiBiZSBjaGFuZ2VkIGJhc2VkIG9uIGltcGxlbWVudGF0aW9uIGZlZWRiYWNrICovXG4gIC8qIHRoaXMgYWxzbyBoYXMgYmlkaSBpbXBsaWNhdGlvbnMgKi9cbiAgLyogdGhpcyBhbHNvIGhhcyBiaWRpIGltcGxpY2F0aW9ucyAqL1xuICAvKiBMVFItc3BlY2lmaWM6IHVzZSAnbWFyZ2luLXJpZ2h0JyBmb3IgcnRsIGVsZW1lbnRzICovXG4gIC8qIExUUi1zcGVjaWZpYzogdXNlICdwYWRkaW5nLXJpZ2h0JyBmb3IgcnRsIGVsZW1lbnRzICovXG4gIC8qdGFibGVbcnVsZXM9bm9uZSBpXSwgdGFibGVbcnVsZXM9Z3JvdXBzIGldLCB0YWJsZVtydWxlcz1yb3dzIGldLFxudGFibGVbcnVsZXM9Y29scyBpXSwgdGFibGVbcnVsZXM9YWxsIGldLCB0YWJsZVtmcmFtZT12b2lkIGldLFxudGFibGVbZnJhbWU9YWJvdmUgaV0sIHRhYmxlW2ZyYW1lPWJlbG93IGldLCB0YWJsZVtmcmFtZT1oc2lkZXMgaV0sXG50YWJsZVtmcmFtZT1saHMgaV0sIHRhYmxlW2ZyYW1lPXJocyBpXSwgdGFibGVbZnJhbWU9dnNpZGVzIGldLFxudGFibGVbZnJhbWU9Ym94IGldLCB0YWJsZVtmcmFtZT1ib3JkZXIgaV0sXG50YWJsZVtydWxlcz1ub25lIGldID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9bm9uZSBpXSA+IHRyID4gdGgsXG50YWJsZVtydWxlcz1ncm91cHMgaV0gPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1ncm91cHMgaV0gPiB0ciA+IHRoLFxudGFibGVbcnVsZXM9cm93cyBpXSA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPXJvd3MgaV0gPiB0ciA+IHRoLFxudGFibGVbcnVsZXM9Y29scyBpXSA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWNvbHMgaV0gPiB0ciA+IHRoLFxudGFibGVbcnVsZXM9YWxsIGldID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9YWxsIGldID4gdHIgPiB0aCxcbnRhYmxlW3J1bGVzPW5vbmUgaV0gPiB0aGVhZCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPW5vbmUgaV0gPiB0aGVhZCA+IHRyID4gdGgsXG50YWJsZVtydWxlcz1ncm91cHMgaV0gPiB0aGVhZCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWdyb3VwcyBpXSA+IHRoZWFkID4gdHIgPiB0aCxcbnRhYmxlW3J1bGVzPXJvd3MgaV0gPiB0aGVhZCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPXJvd3MgaV0gPiB0aGVhZCA+IHRyID4gdGgsXG50YWJsZVtydWxlcz1jb2xzIGldID4gdGhlYWQgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1jb2xzIGldID4gdGhlYWQgPiB0ciA+IHRoLFxudGFibGVbcnVsZXM9YWxsIGldID4gdGhlYWQgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1hbGwgaV0gPiB0aGVhZCA+IHRyID4gdGgsXG50YWJsZVtydWxlcz1ub25lIGldID4gdGJvZHkgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1ub25lIGldID4gdGJvZHkgPiB0ciA+IHRoLFxudGFibGVbcnVsZXM9Z3JvdXBzIGldID4gdGJvZHkgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1ncm91cHMgaV0gPiB0Ym9keSA+IHRyID4gdGgsXG50YWJsZVtydWxlcz1yb3dzIGldID4gdGJvZHkgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1yb3dzIGldID4gdGJvZHkgPiB0ciA+IHRoLFxudGFibGVbcnVsZXM9Y29scyBpXSA+IHRib2R5ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9Y29scyBpXSA+IHRib2R5ID4gdHIgPiB0aCxcbnRhYmxlW3J1bGVzPWFsbCBpXSA+IHRib2R5ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9YWxsIGldID4gdGJvZHkgPiB0ciA+IHRoLFxudGFibGVbcnVsZXM9bm9uZSBpXSA+IHRmb290ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9bm9uZSBpXSA+IHRmb290ID4gdHIgPiB0aCxcbnRhYmxlW3J1bGVzPWdyb3VwcyBpXSA+IHRmb290ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9Z3JvdXBzIGldID4gdGZvb3QgPiB0ciA+IHRoLFxudGFibGVbcnVsZXM9cm93cyBpXSA+IHRmb290ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9cm93cyBpXSA+IHRmb290ID4gdHIgPiB0aCxcbnRhYmxlW3J1bGVzPWNvbHMgaV0gPiB0Zm9vdCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWNvbHMgaV0gPiB0Zm9vdCA+IHRyID4gdGgsXG50YWJsZVtydWxlcz1hbGwgaV0gPiB0Zm9vdCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWFsbCBpXSA+IHRmb290ID4gdHIgPiB0aCB7XG4gICAgYm9yZGVyLWNvbG9yOiBibGFjaztcbn0qL1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCAqLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCAqIHtcbiAgbWFyZ2luOiAwO1xuICBwYWRkaW5nOiAwO1xuICBib3gtc2l6aW5nOiBjb250ZW50LWJveDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYWRkcmVzcyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYWRkcmVzcyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYmxvY2txdW90ZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYmxvY2txdW90ZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgY2VudGVyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBjZW50ZXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpdixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGl2LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBmaWd1cmUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGZpZ3VyZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZmlnY2FwdGlvbixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZmlnY2FwdGlvbixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZm9vdGVyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBmb290ZXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGZvcm0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGZvcm0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGhlYWRlcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaGVhZGVyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBocixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaHIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGxlZ2VuZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbGVnZW5kLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBsaXN0aW5nLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBsaXN0aW5nLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBwLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBwLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBwbGFpbnRleHQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHBsYWludGV4dCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcHJlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBwcmUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHhtcCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgeG1wIHtcbiAgZGlzcGxheTogYmxvY2s7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJsb2NrcXVvdGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJsb2NrcXVvdGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGZpZ3VyZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZmlndXJlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBsaXN0aW5nLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBsaXN0aW5nLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBwLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBwLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBwbGFpbnRleHQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHBsYWludGV4dCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcHJlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBwcmUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHhtcCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgeG1wIHtcbiAgbWFyZ2luLXRvcDogMWVtO1xuICBtYXJnaW4tYm90dG9tOiAxZW07XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJsb2NrcXVvdGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJsb2NrcXVvdGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGZpZ3VyZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZmlndXJlIHtcbiAgbWFyZ2luLWxlZnQ6IDQwcHg7XG4gIG1hcmdpbi1yaWdodDogNDBweDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYWRkcmVzcyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYWRkcmVzcyB7XG4gIGZvbnQtc3R5bGU6IGl0YWxpYztcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbGlzdGluZyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbGlzdGluZyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcGxhaW50ZXh0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBwbGFpbnRleHQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHByZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcHJlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB4bXAsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHhtcCB7XG4gIGZvbnQtZmFtaWx5OiBtb25vc3BhY2U7XG4gIHdoaXRlLXNwYWNlOiBwcmU7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNpdGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNpdGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRmbixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGZuLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBlbSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZW0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGksXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGksXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHZhcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdmFyIHtcbiAgZm9udC1zdHlsZTogaXRhbGljO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBiLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBiLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzdHJvbmcsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHN0cm9uZyB7XG4gIGZvbnQtd2VpZ2h0OiBib2xkZXI7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNvZGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNvZGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGtiZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAga2JkLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzYW1wLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzYW1wLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0dCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdHQge1xuICBmb250LWZhbWlseTogbW9ub3NwYWNlO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBiaWcsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJpZyB7XG4gIGZvbnQtc2l6ZTogbGFyZ2VyO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzbWFsbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc21hbGwge1xuICBmb250LXNpemU6IHNtYWxsZXI7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHN1Yixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc3ViIHtcbiAgdmVydGljYWwtYWxpZ246IHN1Yjtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc3VwLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzdXAge1xuICB2ZXJ0aWNhbC1hbGlnbjogc3VwZXI7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHN1Yixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc3ViLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzdXAsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHN1cCB7XG4gIGxpbmUtaGVpZ2h0OiBub3JtYWw7XG4gIGZvbnQtc2l6ZTogc21hbGxlcjtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcnVieSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcnVieSB7XG4gIGRpc3BsYXk6IHJ1Ynk7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHJiLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCByYiB7XG4gIGRpc3BsYXk6IHJ1YnktYmFzZTtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcnQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHJ0IHtcbiAgZGlzcGxheTogcnVieS10ZXh0O1xuICB3aGl0ZS1zcGFjZTogbm93cmFwO1xuICBmb250LXNpemU6IDUwJTtcbiAgZm9udC12YXJpYW50LWVhc3QtYXNpYW46IHJ1Ynk7XG4gIHRleHQtZW1waGFzaXM6IG5vbmU7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHJiYyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcmJjIHtcbiAgZGlzcGxheTogcnVieS1iYXNlLWNvbnRhaW5lcjtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcnRjLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBydGMge1xuICBkaXNwbGF5OiBydWJ5LXRleHQtY29udGFpbmVyO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBydWJ5LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBydWJ5LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCByYixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcmIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHJ0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBydCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcmJjLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCByYmMsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHJ0Yyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcnRjIHtcbiAgdW5pY29kZS1iaWRpOiBpc29sYXRlO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCA6bGluayxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgOmxpbmsge1xuICBjb2xvcjogIzAwMDBFRTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgOnZpc2l0ZWQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIDp2aXNpdGVkIHtcbiAgY29sb3I6ICM1NTFBOEI7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIDpsaW5rLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCA6bGluayxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgOnZpc2l0ZWQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIDp2aXNpdGVkIHtcbiAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGE6bGlua1tyZWx+PWhlbHBdLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBhOmxpbmtbcmVsfj1oZWxwXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYTp2aXNpdGVkW3JlbH49aGVscF0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGE6dmlzaXRlZFtyZWx+PWhlbHBdLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBhcmVhOmxpbmtbcmVsfj1oZWxwXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYXJlYTpsaW5rW3JlbH49aGVscF0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGFyZWE6dmlzaXRlZFtyZWx+PWhlbHBdLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBhcmVhOnZpc2l0ZWRbcmVsfj1oZWxwXSB7XG4gIGN1cnNvcjogaGVscDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgOmZvY3VzLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCA6Zm9jdXMge1xuICBvdXRsaW5lOiBhdXRvO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBtYXJrLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBtYXJrIHtcbiAgYmFja2dyb3VuZDogeWVsbG93O1xuICBjb2xvcjogYmxhY2s7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGFiYnJbdGl0bGVdLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBhYmJyW3RpdGxlXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYWNyb255bVt0aXRsZV0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGFjcm9ueW1bdGl0bGVdIHtcbiAgdGV4dC1kZWNvcmF0aW9uOiBkb3R0ZWQgdW5kZXJsaW5lO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBpbnMsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGlucyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdSB7XG4gIHRleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkZWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRlbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc3RyaWtlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzdHJpa2Uge1xuICB0ZXh0LWRlY29yYXRpb246IGxpbmUtdGhyb3VnaDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYmxpbmssXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJsaW5rIHtcbiAgdGV4dC1kZWNvcmF0aW9uOiBibGluaztcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcTo6YmVmb3JlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBxOjpiZWZvcmUge1xuICBjb250ZW50OiBvcGVuLXF1b3RlO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBxOjphZnRlcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcTo6YWZ0ZXIge1xuICBjb250ZW50OiBjbG9zZS1xdW90ZTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYnI6OmJlZm9yZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYnI6OmJlZm9yZSB7XG4gIGNvbnRlbnQ6ICdcXEEnO1xuICB3aGl0ZS1zcGFjZTogcHJlO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBub2JyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBub2JyIHtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgd2JyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB3YnIge1xuICBjb250ZW50OiAnXFwyMDBCJztcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbm9iciB3YnIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG5vYnIgd2JyIHtcbiAgd2hpdGUtc3BhY2U6IG5vcm1hbDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYXJ0aWNsZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYXJ0aWNsZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYXNpZGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGFzaWRlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoMSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaDEsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGgyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoMixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaDMsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGgzLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoNCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaDQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGg1LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoNSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaDYsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGg2LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoZ3JvdXAsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGhncm91cCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbmF2LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBuYXYsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHNlY3Rpb24sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHNlY3Rpb24ge1xuICBkaXNwbGF5OiBibG9jaztcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaDEsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGgxIHtcbiAgbWFyZ2luLXRvcDogMC42N2VtO1xuICBtYXJnaW4tYm90dG9tOiAwLjY3ZW07XG4gIGZvbnQtc2l6ZTogMi4wMGVtO1xuICBmb250LXdlaWdodDogYm9sZDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaDIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGgyIHtcbiAgbWFyZ2luLXRvcDogMC44M2VtO1xuICBtYXJnaW4tYm90dG9tOiAwLjgzZW07XG4gIGZvbnQtc2l6ZTogMS41MGVtO1xuICBmb250LXdlaWdodDogYm9sZDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaDMsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGgzIHtcbiAgbWFyZ2luLXRvcDogMS4wMGVtO1xuICBtYXJnaW4tYm90dG9tOiAxLjAwZW07XG4gIGZvbnQtc2l6ZTogMS4xN2VtO1xuICBmb250LXdlaWdodDogYm9sZDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaDQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGg0IHtcbiAgbWFyZ2luLXRvcDogMS4zM2VtO1xuICBtYXJnaW4tYm90dG9tOiAxLjMzZW07XG4gIGZvbnQtc2l6ZTogMS4wMGVtO1xuICBmb250LXdlaWdodDogYm9sZDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaDUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGg1IHtcbiAgbWFyZ2luLXRvcDogMS42N2VtO1xuICBtYXJnaW4tYm90dG9tOiAxLjY3ZW07XG4gIGZvbnQtc2l6ZTogMC44M2VtO1xuICBmb250LXdlaWdodDogYm9sZDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaDYsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGg2IHtcbiAgbWFyZ2luLXRvcDogMi4zM2VtO1xuICBtYXJnaW4tYm90dG9tOiAyLjMzZW07XG4gIGZvbnQtc2l6ZTogMC42N2VtO1xuICBmb250LXdlaWdodDogYm9sZDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRkLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkdCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZHQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIHtcbiAgZGlzcGxheTogYmxvY2s7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGxpLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBsaSB7XG4gIGRpc3BsYXk6IGxpc3QtaXRlbTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwge1xuICBtYXJnaW4tdG9wOiAxZW07XG4gIG1hcmdpbi1ib3R0b206IDFlbTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIGRsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIgZGwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciBvbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIG9sLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGwgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkbCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRsIGRsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkbCBkbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGwgb2wsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRsIG9sLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkbCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGwgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCBkbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wgZGwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIG9sLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCBvbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgZGwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIGRsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCBvbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgb2wsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCB1bCB7XG4gIG1hcmdpbi10b3A6IDA7XG4gIG1hcmdpbi1ib3R0b206IDA7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRkLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkZCB7XG4gIG1hcmdpbi1sZWZ0OiA0MHB4O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwge1xuICBwYWRkaW5nLWxlZnQ6IDQwcHg7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCB7XG4gIGxpc3Qtc3R5bGUtdHlwZTogZGVjaW1hbDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCB7XG4gIGxpc3Qtc3R5bGUtdHlwZTogZGlzYztcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgdWwge1xuICBsaXN0LXN0eWxlLXR5cGU6IGNpcmNsZTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIGRpciBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciBkaXIgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIgZGlyIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIgZGlyIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIgb2wgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIgb2wgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIgb2wgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciBvbCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIHVsIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIHVsIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIHVsIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIgdWwgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIGRpciBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIGRpciBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIGRpciB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wgZGlyIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCBvbCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIG9sIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wgb2wgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIG9sIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCB1bCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIHVsIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wgdWwgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIHVsIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCBkaXIgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCBkaXIgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCBkaXIgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIGRpciB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgb2wgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCBvbCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIG9sIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCBvbCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgdWwgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCB1bCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIHVsIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCB1bCB1bCB7XG4gIGxpc3Qtc3R5bGUtdHlwZTogc3F1YXJlO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0YWJsZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGFibGUge1xuICBkaXNwbGF5OiB0YWJsZTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgY2FwdGlvbixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgY2FwdGlvbiB7XG4gIGRpc3BsYXk6IHRhYmxlLWNhcHRpb247XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNvbGdyb3VwLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBjb2xncm91cCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgY29sZ3JvdXBbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgY29sZ3JvdXBbaGlkZGVuXSB7XG4gIGRpc3BsYXk6IHRhYmxlLWNvbHVtbi1ncm91cDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgY29sLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBjb2wsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNvbFtoaWRkZW5dLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBjb2xbaGlkZGVuXSB7XG4gIGRpc3BsYXk6IHRhYmxlLWNvbHVtbjtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGhlYWQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoZWFkLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0aGVhZFtoaWRkZW5dLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0aGVhZFtoaWRkZW5dIHtcbiAgZGlzcGxheTogdGFibGUtaGVhZGVyLWdyb3VwO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0Ym9keSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGJvZHksXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRib2R5W2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRib2R5W2hpZGRlbl0ge1xuICBkaXNwbGF5OiB0YWJsZS1yb3ctZ3JvdXA7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRmb290LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0Zm9vdCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGZvb3RbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGZvb3RbaGlkZGVuXSB7XG4gIGRpc3BsYXk6IHRhYmxlLWZvb3Rlci1ncm91cDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdHIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0cltoaWRkZW5dLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0cltoaWRkZW5dIHtcbiAgZGlzcGxheTogdGFibGUtcm93O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0ZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0aCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGRbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGRbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGhbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGhbaGlkZGVuXSB7XG4gIGRpc3BsYXk6IHRhYmxlLWNlbGw7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNvbGdyb3VwW2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNvbGdyb3VwW2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNvbFtoaWRkZW5dLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBjb2xbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGhlYWRbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGhlYWRbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGJvZHlbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGJvZHlbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGZvb3RbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGZvb3RbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdHJbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdHJbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGRbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGRbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGhbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGhbaGlkZGVuXSB7XG4gIHZpc2liaWxpdHk6IGNvbGxhcHNlO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0YWJsZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGFibGUge1xuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xuICBib3JkZXItc3BhY2luZzogMnB4O1xuICBib3JkZXItY29sbGFwc2U6IHNlcGFyYXRlO1xuICB0ZXh0LWluZGVudDogaW5pdGlhbDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRkLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0aCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGgge1xuICBwYWRkaW5nOiAxcHg7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0aCB7XG4gIGZvbnQtd2VpZ2h0OiBib2xkO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0aGVhZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGhlYWQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRib2R5LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0Ym9keSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGZvb3QsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRmb290LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0YWJsZSA+IHRyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0YWJsZSA+IHRyIHtcbiAgdmVydGljYWwtYWxpZ246IG1pZGRsZTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdHIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0ZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0aCB7XG4gIHZlcnRpY2FsLWFsaWduOiBpbmhlcml0O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0YWJsZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGFibGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRkLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0ZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGgsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoIHtcbiAgYm9yZGVyLWNvbG9yOiBncmF5O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0aGVhZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGhlYWQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRib2R5LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0Ym9keSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGZvb3QsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRmb290LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0cixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdHIge1xuICBib3JkZXItY29sb3I6IGluaGVyaXQ7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGlucHV0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBpbnB1dCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc2VsZWN0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzZWxlY3QsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9wdGlvbixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb3B0aW9uLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvcHRncm91cCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb3B0Z3JvdXAsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJ1dHRvbixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYnV0dG9uLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0ZXh0YXJlYSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGV4dGFyZWEsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGtleWdlbixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAga2V5Z2VuIHtcbiAgdGV4dC1pbmRlbnQ6IGluaXRpYWw7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRleHRhcmVhLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0ZXh0YXJlYSB7XG4gIHdoaXRlLXNwYWNlOiBwcmUtd3JhcDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaW5wdXRbdHlwZT1cInJhZGlvXCJdLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBpbnB1dFt0eXBlPVwicmFkaW9cIl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGlucHV0W3R5cGU9XCJjaGVja2JveFwiXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaW5wdXRbdHlwZT1cImNoZWNrYm94XCJdLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBpbnB1dFt0eXBlPVwicmVzZXRcIl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGlucHV0W3R5cGU9XCJyZXNldFwiXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaW5wdXRbdHlwZT1cImJ1dHRvblwiXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaW5wdXRbdHlwZT1cImJ1dHRvblwiXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaW5wdXRbdHlwZT1cInN1Ym1pdFwiXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaW5wdXRbdHlwZT1cInN1Ym1pdFwiXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc2VsZWN0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzZWxlY3QsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJ1dHRvbixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYnV0dG9uIHtcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaW5wdXRbdHlwZT1cImJ1dHRvblwiXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaW5wdXRbdHlwZT1cImJ1dHRvblwiXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYnV0dG9uLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBidXR0b24ge1xuICBwYWRkaW5nOiAwLjNlbSAwLjVlbTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaHIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGhyIHtcbiAgY29sb3I6IGdyYXk7XG4gIGJvcmRlci1zdHlsZTogaW5zZXQ7XG4gIGJvcmRlci13aWR0aDogMXB4O1xuICBtYXJnaW46IDAuNWVtIGF1dG87XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGZpZWxkc2V0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBmaWVsZHNldCB7XG4gIG1hcmdpbi1sZWZ0OiAycHg7XG4gIG1hcmdpbi1yaWdodDogMnB4O1xuICBib3JkZXI6IGdyb292ZSAycHggVGhyZWVERmFjZTtcbiAgcGFkZGluZzogMC4zNWVtIDAuNjI1ZW0gMC43NWVtO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBsZWdlbmQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGxlZ2VuZCB7XG4gIHBhZGRpbmctbGVmdDogMnB4O1xuICBwYWRkaW5nLXJpZ2h0OiAycHg7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwID4gKjpmaXJzdC1jaGlsZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgPiAqOmZpcnN0LWNoaWxkIHtcbiAgbWFyZ2luLXRvcDogMCAhaW1wb3J0YW50O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCA+ICo6bGFzdC1jaGlsZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgPiAqOmxhc3QtY2hpbGQge1xuICBtYXJnaW4tYm90dG9tOiAwICFpbXBvcnRhbnQ7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQubGF5b3V0LWNvbnRlbnQtaW1hZ2UgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY29udGVudC1tYXJrdXAgPiBpbWcsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwubGF5b3V0LWNvbnRlbnQtaW1hZ2UgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY29udGVudC1tYXJrdXAgPiBpbWcsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQubGF5b3V0LWNvbnRlbnQtdmVjdG9yLWltYWdlID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNvbnRlbnQtbWFya3VwID4gaW1nLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sLmxheW91dC1jb250ZW50LXZlY3Rvci1pbWFnZSA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1jb250ZW50LW1hcmt1cCA+IGltZyB7XG4gIGRpc3BsYXk6IGJsb2NrO1xuICB3aWR0aDogMTAwJTtcbiAgbWF4LXdpZHRoOiAxMDAlO1xuICBoZWlnaHQ6IGF1dG87XG59XG4ubGF5b3V0LWVkaXRvciAuaW1nLXJlc3BvbnNpdmUsXG4ubGF5b3V0LWVkaXRvciAuaW1nLXJlc3BvbnNpdmUgaW1nIHtcbiAgZGlzcGxheTogYmxvY2s7XG4gIHdpZHRoOiAxMDAlO1xuICBtYXgtd2lkdGg6IDEwMCU7XG4gIGhlaWdodDogYXV0bztcbn1cblxuLmxheW91dC1lZGl0b3IgPiAubGF5b3V0LXRvb2xib3gtd3JhcHBlciB7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgbWFyZ2luLWxlZnQ6IDEycHg7XG4gIHdpZHRoOiAyMjBweDtcbiAgZmxleC1zaHJpbms6IDA7XG59XG4ubGF5b3V0LWVkaXRvciA+IC5sYXlvdXQtdG9vbGJveC13cmFwcGVyID4gLmxheW91dC10b29sYm94IHtcbiAgYm9yZGVyOiAxcHggc29saWQgI2U0ZTVlNjtcbiAgd2lkdGg6IDIyMHB4O1xuICBtaW4taGVpZ2h0OiA0MDBweDtcbiAgcGFkZGluZzogNnB4O1xuICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjNmNGY1O1xufVxuLmxheW91dC1lZGl0b3IgPiAubGF5b3V0LXRvb2xib3gtd3JhcHBlciA+IC5sYXlvdXQtdG9vbGJveC5zdGlja3ktdG9wIHtcbiAgcG9zaXRpb246IGZpeGVkO1xuICB0b3A6IDA7XG4gIG1heC1oZWlnaHQ6IDEwMCU7XG4gIG92ZXJmbG93LXk6IGF1dG87XG59XG4ubGF5b3V0LWVkaXRvciA+IC5sYXlvdXQtdG9vbGJveC13cmFwcGVyID4gLmxheW91dC10b29sYm94LnN0aWNreS1ib3R0b20ge1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIGJvdHRvbTogMDtcbn1cbi5sYXlvdXQtZWRpdG9yID4gLmxheW91dC10b29sYm94LXdyYXBwZXIgPiAubGF5b3V0LXRvb2xib3ggLmxheW91dC10b29sYm94LWdyb3VwIHtcbiAgbWFyZ2luLXRvcDogMTJweDtcbn1cbi5sYXlvdXQtZWRpdG9yID4gLmxheW91dC10b29sYm94LXdyYXBwZXIgPiAubGF5b3V0LXRvb2xib3ggLmxheW91dC10b29sYm94LWdyb3VwIC5sYXlvdXQtdG9vbGJveC1ncm91cC1oZWFkaW5nIHtcbiAgZGlzcGxheTogYmxvY2s7XG4gIG1hcmdpbi1ib3R0b206IDRweDtcbiAgdGV4dC1kZWNvcmF0aW9uOiBub25lO1xufVxuLmxheW91dC1lZGl0b3IgPiAubGF5b3V0LXRvb2xib3gtd3JhcHBlciA+IC5sYXlvdXQtdG9vbGJveCAubGF5b3V0LXRvb2xib3gtZ3JvdXAgLmxheW91dC10b29sYm94LWdyb3VwLWhlYWRpbmc6YmVmb3JlIHtcbiAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICB3aWR0aDogMTBweDtcbiAgbWFyZ2luLXJpZ2h0OiA0cHg7XG4gIGZvbnQ6IG5vcm1hbCBub3JtYWwgbm9ybWFsIDE0cHgvMSBGb250QXdlc29tZTtcbiAgdGV4dC1hbGlnbjogY2VudGVyO1xuICBjb250ZW50OiBcIlxcZjBkN1wiO1xufVxuLmxheW91dC1lZGl0b3IgPiAubGF5b3V0LXRvb2xib3gtd3JhcHBlciA+IC5sYXlvdXQtdG9vbGJveCAubGF5b3V0LXRvb2xib3gtZ3JvdXAuY29sbGFwc2VkIC5sYXlvdXQtdG9vbGJveC1ncm91cC1oZWFkaW5nOmJlZm9yZSB7XG4gIGNvbnRlbnQ6IFwiXFxmMGRhXCI7XG59XG4ubGF5b3V0LWVkaXRvciA+IC5sYXlvdXQtdG9vbGJveC13cmFwcGVyID4gLmxheW91dC10b29sYm94IC5sYXlvdXQtdG9vbGJveC1ncm91cC5jb2xsYXBzZWQgLmxheW91dC10b29sYm94LWl0ZW1zIHtcbiAgZGlzcGxheTogbm9uZTtcbn1cbi5sYXlvdXQtZWRpdG9yID4gLmxheW91dC10b29sYm94LXdyYXBwZXIgPiAubGF5b3V0LXRvb2xib3ggLmxheW91dC10b29sYm94LWdyb3VwIC5sYXlvdXQtdG9vbGJveC1zZWN0aW9uICsgLmxheW91dC10b29sYm94LXNlY3Rpb24ge1xuICBtYXJnaW4tdG9wOiA0cHg7XG59XG4ubGF5b3V0LWVkaXRvciA+IC5sYXlvdXQtdG9vbGJveC13cmFwcGVyID4gLmxheW91dC10b29sYm94IC5sYXlvdXQtdG9vbGJveC1ncm91cCAubGF5b3V0LXRvb2xib3gtaXRlbSB7XG4gIGJvcmRlcjogMXB4IHNvbGlkICNlNGU1ZTY7XG4gIGJhY2tncm91bmQtY29sb3I6ICNmZmY7XG4gIHBhZGRpbmc6IDlweCAxMnB4O1xuICBjdXJzb3I6IGRlZmF1bHQ7XG59XG4ubGF5b3V0LWVkaXRvciA+IC5sYXlvdXQtdG9vbGJveC13cmFwcGVyID4gLmxheW91dC10b29sYm94IC5sYXlvdXQtdG9vbGJveC1ncm91cCAubGF5b3V0LXRvb2xib3gtaXRlbSBpIHtcbiAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICB3aWR0aDogMTZweDtcbiAgZm9udDogbm9ybWFsIG5vcm1hbCBub3JtYWwgMTRweC8xIEZvbnRBd2Vzb21lO1xufVxuLmxheW91dC1lZGl0b3IgPiAubGF5b3V0LXRvb2xib3gtd3JhcHBlciA+IC5sYXlvdXQtdG9vbGJveCAubGF5b3V0LXRvb2xib3gtZ3JvdXAgLmxheW91dC10b29sYm94LWl0ZW0gKyAubGF5b3V0LXRvb2xib3gtaXRlbSB7XG4gIG1hcmdpbi10b3A6IDRweDtcbn1cbi5sYXlvdXQtZWRpdG9yID4gLmxheW91dC10b29sYm94LXdyYXBwZXIgPiAubGF5b3V0LXRvb2xib3ggLmxheW91dC10b29sYm94LWdyb3VwICsgLmxheW91dC10b29sYm94LWdyb3VwIHtcbiAgbWFyZ2luLXRvcDogNnB4O1xufVxuXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LXBvcHVwIHtcbiAgZGlzcGxheTogbm9uZTtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICBtYXJnaW46IDA7XG4gIC1tb3otYm94LXNoYWRvdzogM3B4IDNweCAxMXB4IDAgcmdiYSg1MCwgNTAsIDUwLCAwLjUpO1xuICAtd2Via2l0LWJveC1zaGFkb3c6IDNweCAzcHggMTFweCAwIHJnYmEoNTAsIDUwLCA1MCwgMC41KTtcbiAgYm94LXNoYWRvdzogM3B4IDNweCAxMXB4IDAgcmdiYSg1MCwgNTAsIDUwLCAwLjUpO1xuICBib3JkZXI6IDFweCBzb2xpZCAjZTRlNWU2O1xuICBwYWRkaW5nOiAycHggMDtcbiAgYmFja2dyb3VuZC1jb2xvcjogI2Y3ZjdmNztcbiAgbGlzdC1zdHlsZTogbm9uZTtcbiAgei1pbmRleDogMjA7XG4gIGNvbG9yOiAjN2M3YzdjO1xuICB0ZXh0LWFsaWduOiBsZWZ0O1xuICBjdXJzb3I6IGRlZmF1bHQ7XG4gIHdoaXRlLXNwYWNlOiBub3dyYXA7XG4gIGxpbmUtaGVpZ2h0OiBub3JtYWw7XG4gIG1pbi13aWR0aDogMzAwcHg7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LXBvcHVwLndpZGUge1xuICB3aWR0aDogNjAwcHg7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LXBvcHVwIC5sYXlvdXQtcG9wdXAtZmxleCB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIHBhZGRpbmc6IDJweCA1cHg7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LXBvcHVwIC5sYXlvdXQtcG9wdXAtZmxleCAubGF5b3V0LXBvcHVwLWNvbHVtbiArIC5sYXlvdXQtcG9wdXAtY29sdW1uIHtcbiAgbWFyZ2luLWxlZnQ6IDRweDtcbiAgYm9yZGVyLWxlZnQ6IDFweCBzb2xpZCByZ2JhKDEyOCwgMTI4LCAxMjgsIDAuMTUpO1xuICBwYWRkaW5nLWxlZnQ6IDRweDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtcG9wdXAgLmxheW91dC1wb3B1cC1pdGVtIHtcbiAgcGFkZGluZzogNHB4IDZweDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtcG9wdXAgLmxheW91dC1wb3B1cC1sYWJlbCB7XG4gIGZvbnQtc2l6ZTogMC45ZW07XG4gIGZvbnQtd2VpZ2h0OiBib2xkO1xuICBjb2xvcjogIzdjN2M3Yztcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtcG9wdXAgLmxheW91dC1wb3B1cC1hY3Rpb246aG92ZXIge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjNmNGY1O1xuICBjdXJzb3I6IHBvaW50ZXI7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LXBvcHVwIC5sYXlvdXQtcG9wdXAtaW5wdXQgaW5wdXRbdHlwZT0ndGV4dCddLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1wb3B1cCAubGF5b3V0LXBvcHVwLWlucHV0IHRleHRhcmVhIHtcbiAgd2lkdGg6IDEwMCU7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LXBvcHVwIC5sYXlvdXQtcG9wdXAtaW5wdXQgPiBsYWJlbCB7XG4gIGRpc3BsYXk6IGJsb2NrO1xuICBmb250LXNpemU6IDAuOWVtO1xufVxuIiwi77u/QGltcG9ydCBcIlZhcmlhYmxlcy5sZXNzXCI7XHJcblxyXG4ubGF5b3V0LWVkaXRvciB7XHJcbiAgICAubGF5b3V0LWVsZW1lbnQge1xyXG4gICAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcclxuICAgICAgICBtYXJnaW4tdG9wOiAwO1xyXG4gICAgICAgIG1hcmdpbi1yaWdodDogMDtcclxuICAgICAgICBtYXJnaW4tYm90dG9tOiAwO1xyXG4gICAgICAgIHBhZGRpbmc6IDA7XHJcblxyXG4gICAgICAgIC8vIFdlIGRvbid0IGZ1Y2sgd2l0aCB0aGUgbGVmdCBtYXJnaW4gb2YgY29sdW1ucywgYmVjYXVzZSBCb290c3RyYXAgdXNlcyB0aGVzZSB0byByZW5kZXIgY29sdW1uIG9mZnNldHMuXHJcbiAgICAgICAgJjpub3QoLmxheW91dC1jb2x1bW4pIHtcclxuICAgICAgICAgICAgbWFyZ2luLWxlZnQ6IDA7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIHtcclxuICAgICAgICAgICAgPiAubGF5b3V0LXBhbmVsIHtcclxuICAgICAgICAgICAgICAgIGRpc3BsYXk6IG5vbmU7IC8vIFNob3duIG9ubHkgaW4gYWN0aXZlIG9yIGZvY3VzZWQgc3RhdGVzLlxyXG4gICAgICAgICAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xyXG4gICAgICAgICAgICAgICAgbWFyZ2luOiAwO1xyXG4gICAgICAgICAgICAgICAgei1pbmRleDogMjA7XHJcbiAgICAgICAgICAgICAgICBoZWlnaHQ6IDI1cHg7XHJcbiAgICAgICAgICAgICAgICBwYWRkaW5nOiAwIDZweDtcclxuICAgICAgICAgICAgICAgIGxpc3Qtc3R5bGU6IG5vbmU7XHJcbiAgICAgICAgICAgICAgICB3aGl0ZS1zcGFjZTogbm93cmFwO1xyXG4gICAgICAgICAgICAgICAgbGluZS1oZWlnaHQ6IDI1cHg7XHJcbiAgICAgICAgICAgICAgICB2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlO1xyXG5cclxuICAgICAgICAgICAgICAgID4gLmxheW91dC1wYW5lbC1pdGVtIHtcclxuICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XHJcbiAgICAgICAgICAgICAgICAgICAgaGVpZ2h0OiAyNXB4O1xyXG4gICAgICAgICAgICAgICAgICAgIHBhZGRpbmc6IDFweCA2cHggMDtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICA+IC5sYXlvdXQtcGFuZWwtbGFiZWwge1xyXG4gICAgICAgICAgICAgICAgICAgIGZvbnQtc2l6ZTogQGZvbnQtc2l6ZSAtIDE7XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgPiAubGF5b3V0LXBhbmVsLWFjdGlvbiB7XHJcbiAgICAgICAgICAgICAgICAgICAgZGlzcGxheTogbm9uZTsgLy8gU2hvd24gb25seSBpbiBmb2N1c2VkIHN0YXRlLlxyXG4gICAgICAgICAgICAgICAgICAgIHdpZHRoOiAyOHB4O1xyXG4gICAgICAgICAgICAgICAgICAgIGN1cnNvcjogcG9pbnRlcjtcclxuICAgICAgICAgICAgICAgICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgID4gLmxheW91dC1wYW5lbC1tYWluIHtcclxuICAgICAgICAgICAgICAgIHRvcDogLTI3cHg7XHJcbiAgICAgICAgICAgICAgICBsZWZ0OiAtMnB4O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFdoZW4gZHJhZ2dpbmcgZnJvbSB0b29sYm94LCBlbGVtZW50cyB3aWxsIGJlIGxpIHJhdGhlciB0aGFuIGRpdi5cclxuICAgIGxpLmxheW91dC1lbGVtZW50IHtcclxuICAgICAgICBsaXN0LXN0eWxlOiBub25lO1xyXG4gICAgfVxyXG5cclxuICAgICY6bm90KC5sYXlvdXQtZWRpdG9yLWRyYWdnaW5nKSB7XHJcblxyXG4gICAgICAgIC5sYXlvdXQtZWxlbWVudC1hY3RpdmUsIC5sYXlvdXQtZWxlbWVudC1mb2N1c2VkIHtcclxuICAgICAgICAgICAgYm9yZGVyLXdpZHRoOiAycHg7XHJcbiAgICAgICAgICAgIGJvcmRlci1zdHlsZTogc29saWQ7XHJcblxyXG4gICAgICAgICAgICA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIHtcclxuICAgICAgICAgICAgICAgIG1hcmdpbjogLTJweDtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLmxheW91dC1lbGVtZW50LWFjdGl2ZSB7XHJcbiAgICAgICAgICAgIEBhY3RpdmUtaGlnaGxpZ2h0OiBmYWRlKCM2ODY4NjgsIDEwJSk7XHJcblxyXG4gICAgICAgICAgICBib3JkZXItY29sb3I6IEBhY3RpdmUtaGlnaGxpZ2h0O1xyXG5cclxuICAgICAgICAgICAgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtcGFuZWwtbWFpbiB7XHJcbiAgICAgICAgICAgICAgICBkaXNwbGF5OiBibG9jazsgLy8gVG8gcmV2ZWFsLlxyXG4gICAgICAgICAgICAgICAgei1pbmRleDogMzA7XHJcbiAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiBAYWN0aXZlLWhpZ2hsaWdodDtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLmxheW91dC1lbGVtZW50LWZvY3VzZWQge1xyXG4gICAgICAgICAgICBAZm9jdXNlZC1oaWdobGlnaHQ6ICM2NDg3MjE7XHJcbiAgICAgICAgICAgIEBmb2N1c2VkLXRleHQ6ICNmZWZlZmU7XHJcblxyXG4gICAgICAgICAgICBib3JkZXItY29sb3I6IEBmb2N1c2VkLWhpZ2hsaWdodDtcclxuXHJcbiAgICAgICAgICAgID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LXBhbmVsIHtcclxuICAgICAgICAgICAgICAgIGRpc3BsYXk6IGJsb2NrOyAvLyBUbyByZXZlYWwuXHJcbiAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiBAZm9jdXNlZC1oaWdobGlnaHQ7XHJcbiAgICAgICAgICAgICAgICBjb2xvcjogQGZvY3VzZWQtdGV4dDtcclxuXHJcbiAgICAgICAgICAgICAgICA+IC5sYXlvdXQtcGFuZWwtYWN0aW9uIHtcclxuICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IC8vIFRvIHJldmVhbC5cclxuICAgICAgICAgICAgICAgICAgICAmOmhvdmVyIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogbGlnaHRlbihAZm9jdXNlZC1oaWdobGlnaHQsIDEwJSk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAmLmRpc2FibGVkIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY3Vyc29yOiBkZWZhdWx0O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb2xvcjogZmFkZShAZm9jdXNlZC10ZXh0LCA0MCUpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgJjpob3ZlciB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiBAZm9jdXNlZC1oaWdobGlnaHQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICYuYWN0aXZlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I6IGxpZ2h0ZW4oc2F0dXJhdGUoc3BpbihAZm9jdXNlZC1oaWdobGlnaHQsIC0xMCksIDEwMCUpLCAzMCUpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGVuKEBmb2N1c2VkLWhpZ2hsaWdodCwgNSUpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgJjpob3ZlciB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGVuKEBmb2N1c2VkLWhpZ2hsaWdodCwgMTAlKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLmxheW91dC1lbGVtZW50LXNlbGVjdGVkIHtcclxuICAgICAgICAgICAgQHNlbGVjdGVkLWhpZ2hsaWdodDogIzY0ODcyMTtcclxuICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogZmFkZShAc2VsZWN0ZWQtaGlnaGxpZ2h0LCA4JSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC51aS1zb3J0YWJsZS1wbGFjZWhvbGRlciB7XHJcbiAgICAgICAgZGlzcGxheTogbm9uZTtcclxuICAgIH1cclxuXHJcbiAgICAubGF5b3V0LWVsZW1lbnQtZHJvcHRhcmdldCB7XHJcbiAgICAgICAgQGRyb3B0YXJnZXQtaGlnaGxpZ2h0OiAjNjQ4NzIxO1xyXG4gICAgICAgIGJveC1zaGFkb3c6IGluc2V0IDAgMCAxMnB4IDZweCBmYWRlKEBkcm9wdGFyZ2V0LWhpZ2hsaWdodCwgNTAlKTtcclxuXHJcbiAgICAgICAgLnVpLXNvcnRhYmxlLXBsYWNlaG9sZGVyIHtcclxuICAgICAgICAgICAgZGlzcGxheTogYmxvY2s7IC8vIFRvIHJldmVhbC5cclxuICAgICAgICAgICAgdmlzaWJpbGl0eTogdmlzaWJsZSAhaW1wb3J0YW50O1xyXG4gICAgICAgICAgICBtaW4taGVpZ2h0OiBAZWxlbWVudC1taW4taGVpZ2h0IC0gMnB4O1xyXG4gICAgICAgICAgICBib3JkZXI6IDJweCBkYXNoZWQgQGRyb3B0YXJnZXQtaGlnaGxpZ2h0ICFpbXBvcnRhbnQ7XHJcbiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IGZhZGUoQGRyb3B0YXJnZXQtaGlnaGxpZ2h0LCAxNiUpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBBIENTUyBmaXggZm9yIG1lZGlhIGl0ZW0gZWxlbWVudHMuXHJcbiAgICAubWVkaWEtdGh1bWJuYWlsIHtcclxuICAgICAgICBpbWcge1xyXG4gICAgICAgICAgICBtYXgtd2lkdGg6MTAwJTtcclxuICAgICAgICAgICAgbWF4LWhlaWdodDogMTAwJTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn1cclxuIiwi77u/QGltcG9ydCBcIlZhcmlhYmxlcy5sZXNzXCI7XHJcblxyXG4ubGF5b3V0LWVkaXRvciB7XHJcbiAgICAubGF5b3V0LWNvbnRhaW5lciB7XHJcblxyXG4gICAgICAgID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIge1xyXG5cclxuICAgICAgICAgICAgPiAubGF5b3V0LWNvbnRhaW5lci1jaGlsZHJlbi1wbGFjZWhvbGRlciB7XHJcbiAgICAgICAgICAgICAgICBkaXNwbGF5OiBub25lO1xyXG4gICAgICAgICAgICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgICAgICAgICAgICAgIG1hcmdpbjogQGNvbnRhaW5lci1wYWRkaW5nIC0gMXB4O1xyXG4gICAgICAgICAgICAgICAgbWluLWhlaWdodDogQGVsZW1lbnQtbWluLWhlaWdodDtcclxuICAgICAgICAgICAgICAgIGJvcmRlcjogMXB4IGRhc2hlZCBmYWRlKEBncmF5LXRleHQsIDQwJSk7XHJcbiAgICAgICAgICAgICAgICBib3JkZXItcmFkaXVzOiA0cHg7XHJcbiAgICAgICAgICAgICAgICBwYWRkaW5nOiBAY29udGFpbmVyLXBhZGRpbmc7XHJcbiAgICAgICAgICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcclxuICAgICAgICAgICAgICAgIGZvbnQtc2l6ZTogQGZvbnQtc2l6ZSAtIDE7XHJcbiAgICAgICAgICAgICAgICBmb250LXN0eWxlOiBpdGFsaWM7XHJcbiAgICAgICAgICAgICAgICBvcGFjaXR5OiAwLjY7XHJcbiAgICAgICAgICAgICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgID4gLmxheW91dC1jaGlsZHJlbiB7XHJcbiAgICAgICAgICAgICAgICBwYWRkaW5nOiBAY29udGFpbmVyLXBhZGRpbmc7XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gQWxsIGFkamFjZW50IG5vbi1jb250YWluZXIgY2hpbGRyZW4gbmVlZCBzb21lIHNwYWNlIGJldHdlZW4uLi5cclxuICAgICAgICAgICAgICAgID4gLmxheW91dC1lbGVtZW50Om5vdCgubGF5b3V0LWNvbnRhaW5lcikgKyAubGF5b3V0LWVsZW1lbnQ6bm90KC5sYXlvdXQtY29udGFpbmVyKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgbWFyZ2luLXRvcDogQGNvbnRlbnQtc3BhY2luZztcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAvLyAuLi4gZXhjZXB0IHdoZW4galF1ZXJ5IFVJIHNvcnRhYmxlIGhlbHBlciBpcyB0aGUgZmlyc3QgZWxlbWVudCAoYmVjYXVzZSB0aGF0IG9uZSBpcyBhYnNvbHV0ZWx5IHBvc2l0aW9uZWQgYW5kIFwiZmxvYXRpbmdcIikuXHJcbiAgICAgICAgICAgICAgICA+IC51aS1zb3J0YWJsZS1oZWxwZXI6Zmlyc3QtY2hpbGQgKyAubGF5b3V0LWVsZW1lbnQ6bm90KC5sYXlvdXQtY29udGFpbmVyKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgbWFyZ2luLXRvcDogMDtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgJi5sYXlvdXQtY29udGFpbmVyLWVtcHR5IHtcclxuICAgICAgICAgICAgICAgID4gLmxheW91dC1jb250YWluZXItY2hpbGRyZW4tcGxhY2Vob2xkZXIge1xyXG4gICAgICAgICAgICAgICAgICAgIGRpc3BsYXk6IGZsZXg7IC8vIFRvIHJldmVhbC5cclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICA+IC5sYXlvdXQtY2hpbGRyZW4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgICAgICAgICAgICAgICAgICB0b3A6IDA7XHJcbiAgICAgICAgICAgICAgICAgICAgcmlnaHQ6IDA7XHJcbiAgICAgICAgICAgICAgICAgICAgYm90dG9tOiAwO1xyXG4gICAgICAgICAgICAgICAgICAgIGxlZnQ6IDA7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgJjpub3QoLmxheW91dC1lZGl0b3ItZHJhZ2dpbmcpIHtcclxuICAgICAgICAubGF5b3V0LWNvbnRhaW5lci5sYXlvdXQtZWxlbWVudC1mb2N1c2VkID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNoaWxkcmVuIHtcclxuICAgICAgICAgICAgPiAubGF5b3V0LWVsZW1lbnQ6bm90KC5sYXlvdXQtZWxlbWVudC1hY3RpdmUpIHtcclxuICAgICAgICAgICAgICAgIGJvcmRlcjogMXB4IGRhc2hlZCBmYWRlKEBncmF5LXRleHQsIDYwJSk7XHJcblxyXG4gICAgICAgICAgICAgICAgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciB7XHJcbiAgICAgICAgICAgICAgICAgICAgbWFyZ2luOiAtMXB4O1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICA+IC5sYXlvdXQtY29udGFpbmVyICsgLmxheW91dC1jb250YWluZXI6bm90KC5sYXlvdXQtZWxlbWVudC1hY3RpdmUpIHtcclxuICAgICAgICAgICAgICAgIGJvcmRlci10b3A6IDA7XHJcblxyXG4gICAgICAgICAgICAgICAgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciB7XHJcbiAgICAgICAgICAgICAgICAgICAgbWFyZ2luLXRvcDogMDtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG4iLCLvu79AaW1wb3J0IFwiVmFyaWFibGVzLmxlc3NcIjtcclxuXHJcbi5sYXlvdXQtZWRpdG9yIHtcclxuICAgIC5sYXlvdXQtY2FudmFzIHtcclxuICAgICAgICAjZHVtbXkgeyAvLyBPbmx5IGFkZGVkIGJlY2F1c2UgV0UgZG9lc24ndCBjb21waWxlIGlmIHRoZXJlIGFyZSBubyBydWxlcy5cclxuICAgICAgICAgICAgZGlzcGxheTogbm9uZTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn0iLCLvu79AaW1wb3J0IFwiVmFyaWFibGVzLmxlc3NcIjtcclxuXHJcbi5sYXlvdXQtZWRpdG9yIHtcclxuICAgIC5sYXlvdXQtcm93IHtcclxuICAgICAgICAmLmxheW91dC1lbGVtZW50LWZvY3VzZWQ6bm90KC5sYXlvdXQtZWxlbWVudC1kcm9wdGFyZ2V0KSA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1jaGlsZHJlbiB7XHJcbiAgICAgICAgICAgID4gLmxheW91dC1lbGVtZW50Om5vdCgubGF5b3V0LWVsZW1lbnQtYWN0aXZlKSB7XHJcbiAgICAgICAgICAgICAgICBib3JkZXItdG9wOiAxcHggZGFzaGVkIGZhZGUoQGdyYXktdGV4dCwgNjAlKSAhaW1wb3J0YW50O1xyXG4gICAgICAgICAgICAgICAgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciB7XHJcbiAgICAgICAgICAgICAgICAgICAgbWFyZ2luLXRvcDogLTFweCAhaW1wb3J0YW50O1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICA+IC5sYXlvdXQtZWxlbWVudCArIC5sYXlvdXQtZWxlbWVudDpub3QoLmxheW91dC1lbGVtZW50LWFjdGl2ZSkge1xyXG4gICAgICAgICAgICAgICAgYm9yZGVyLWxlZnQ6IDAgIWltcG9ydGFudDtcclxuICAgICAgICAgICAgICAgID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIge1xyXG4gICAgICAgICAgICAgICAgICAgIG1hcmdpbi1sZWZ0OiAwICFpbXBvcnRhbnQ7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcbn0iLCLvu79AaW1wb3J0IFwiVmFyaWFibGVzLmxlc3NcIjtcclxuXHJcbi5sYXlvdXQtZWRpdG9yIHtcclxuICAgIC5sYXlvdXQtY29sdW1uIHtcclxuICAgICAgICA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIHtcclxuICAgICAgICAgICAgPiAubGF5b3V0LWNvbHVtbi1yZXNpemUtYmFyIHtcclxuICAgICAgICAgICAgICAgIGRpc3BsYXk6IG5vbmU7XHJcbiAgICAgICAgICAgICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgICAgICAgICAgICAgICB6LWluZGV4OiAzMDtcclxuICAgICAgICAgICAgICAgIHRvcDogMDtcclxuICAgICAgICAgICAgICAgIHdpZHRoOiAxNnB4O1xyXG4gICAgICAgICAgICAgICAgaGVpZ2h0OiAxMDAlO1xyXG4gICAgICAgICAgICAgICAgY3Vyc29yOiBjb2wtcmVzaXplO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICA+IC5sYXlvdXQtY29sdW1uLXJlc2l6ZS1iYXItbGVmdCB7XHJcbiAgICAgICAgICAgICAgICBsZWZ0OiAtNnB4O1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICA+IC5sYXlvdXQtY29sdW1uLXJlc2l6ZS1iYXItcmlnaHQge1xyXG4gICAgICAgICAgICAgICAgcmlnaHQ6IC02cHg7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICYubGF5b3V0LWVsZW1lbnQtZm9jdXNlZCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1jb2x1bW4tcmVzaXplLWJhciB7XHJcbiAgICAgICAgICAgIGRpc3BsYXk6IGJsb2NrO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG4iLCLvu79AaW1wb3J0IFwiVmFyaWFibGVzLmxlc3NcIjtcclxuQGltcG9ydCBcIlJlc2V0Lmxlc3NcIjtcclxuXHJcbi5sYXlvdXQtZWRpdG9yIHtcclxuICAgIC5sYXlvdXQtY29udGVudCwgLmxheW91dC1odG1sIHtcclxuICAgICAgICBtaW4taGVpZ2h0OiAxZW07XHJcblxyXG4gICAgICAgID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIge1xyXG4gICAgICAgICAgICAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHtcclxuXHJcbiAgICAgICAgICAgICAgICBwYWRkaW5nOiAycHg7XHJcbiAgICAgICAgICAgICAgICBvdmVyZmxvdy14OiBoaWRkZW47XHJcbiAgICAgICAgICAgICAgICBsaW5lLWhlaWdodDogbm9ybWFsO1xyXG5cclxuICAgICAgICAgICAgICAgIC8vIFJlc2V0IHRvIEhUTUw1IFczQyBzdGFuZGFyZCBkZWZhdWx0IHN0eWxpbmcgd2l0aGluIGNvbnRlbnQuXHJcbiAgICAgICAgICAgICAgICAucmVzZXQoKTtcclxuXHJcbiAgICAgICAgICAgICAgICA+ICo6Zmlyc3QtY2hpbGQge1xyXG4gICAgICAgICAgICAgICAgICAgIG1hcmdpbi10b3A6IDAgIWltcG9ydGFudDsgLy8gSW1wb3J0YW50IGJlY2F1c2Ugc2l0ZS5jc3Mgb2YgdGhlIGFkbWluIHRoZW1lIHN0eWxlcyBoZWFkaW5nIG1hcmdpbnMgd2l0aCBhIHZlcnkgaGlnaCBzcGVjaWZpY2l0eS5cclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICA+ICo6bGFzdC1jaGlsZCB7XHJcbiAgICAgICAgICAgICAgICAgICAgbWFyZ2luLWJvdHRvbTogMCAhaW1wb3J0YW50O1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAmLmxheW91dC1jb250ZW50LWltYWdlLCAmLmxheW91dC1jb250ZW50LXZlY3Rvci1pbWFnZSB7XHJcbiAgICAgICAgICAgID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNvbnRlbnQtbWFya3VwID4gaW1nIHtcclxuICAgICAgICAgICAgICAgIGRpc3BsYXk6IGJsb2NrO1xyXG4gICAgICAgICAgICAgICAgd2lkdGg6IDEwMCU7XHJcbiAgICAgICAgICAgICAgICBtYXgtd2lkdGg6IDEwMCU7XHJcbiAgICAgICAgICAgICAgICBoZWlnaHQ6IGF1dG87XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLmltZy1yZXNwb25zaXZlLCAuaW1nLXJlc3BvbnNpdmUgaW1nIHtcclxuICAgICAgICBkaXNwbGF5OiBibG9jaztcclxuICAgICAgICB3aWR0aDogMTAwJTtcclxuICAgICAgICBtYXgtd2lkdGg6IDEwMCU7XHJcbiAgICAgICAgaGVpZ2h0OiBhdXRvO1xyXG4gICAgfVxyXG59XHJcbiIsIu+7vy5yZXNldCgpIHtcclxuXHJcbiAgICAqIHtcclxuICAgICAgICBtYXJnaW46IDA7XHJcbiAgICAgICAgcGFkZGluZzogMDtcclxuICAgICAgICBib3gtc2l6aW5nOiBjb250ZW50LWJveDtcclxuICAgIH1cclxuXHJcbiAgICBhZGRyZXNzLCBibG9ja3F1b3RlLCBjZW50ZXIsIGRpdiwgZmlndXJlLCBmaWdjYXB0aW9uLCBmb290ZXIsIGZvcm0sXHJcbiAgICBoZWFkZXIsIGhyLCBsZWdlbmQsIGxpc3RpbmcsIHAsIHBsYWludGV4dCwgcHJlLCB4bXAge1xyXG4gICAgICAgIGRpc3BsYXk6IGJsb2NrO1xyXG4gICAgfVxyXG5cclxuICAgIGJsb2NrcXVvdGUsIGZpZ3VyZSwgbGlzdGluZywgcCwgcGxhaW50ZXh0LCBwcmUsIHhtcCB7XHJcbiAgICAgICAgbWFyZ2luLXRvcDogMWVtO1xyXG4gICAgICAgIG1hcmdpbi1ib3R0b206IDFlbTtcclxuICAgIH1cclxuXHJcbiAgICBibG9ja3F1b3RlLCBmaWd1cmUge1xyXG4gICAgICAgIG1hcmdpbi1sZWZ0OiA0MHB4O1xyXG4gICAgICAgIG1hcmdpbi1yaWdodDogNDBweDtcclxuICAgIH1cclxuXHJcbiAgICBhZGRyZXNzIHtcclxuICAgICAgICBmb250LXN0eWxlOiBpdGFsaWM7XHJcbiAgICB9XHJcblxyXG4gICAgbGlzdGluZywgcGxhaW50ZXh0LCBwcmUsIHhtcCB7XHJcbiAgICAgICAgZm9udC1mYW1pbHk6IG1vbm9zcGFjZTtcclxuICAgICAgICB3aGl0ZS1zcGFjZTogcHJlO1xyXG4gICAgfVxyXG5cclxuICAgIGNpdGUsIGRmbiwgZW0sIGksIHZhciB7XHJcbiAgICAgICAgZm9udC1zdHlsZTogaXRhbGljO1xyXG4gICAgfVxyXG5cclxuICAgIGIsIHN0cm9uZyB7XHJcbiAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGRlcjtcclxuICAgIH1cclxuXHJcbiAgICBjb2RlLCBrYmQsIHNhbXAsIHR0IHtcclxuICAgICAgICBmb250LWZhbWlseTogbW9ub3NwYWNlO1xyXG4gICAgfVxyXG5cclxuICAgIGJpZyB7XHJcbiAgICAgICAgZm9udC1zaXplOiBsYXJnZXI7XHJcbiAgICB9XHJcblxyXG4gICAgc21hbGwge1xyXG4gICAgICAgIGZvbnQtc2l6ZTogc21hbGxlcjtcclxuICAgIH1cclxuXHJcbiAgICBzdWIge1xyXG4gICAgICAgIHZlcnRpY2FsLWFsaWduOiBzdWI7XHJcbiAgICB9XHJcblxyXG4gICAgc3VwIHtcclxuICAgICAgICB2ZXJ0aWNhbC1hbGlnbjogc3VwZXI7XHJcbiAgICB9XHJcblxyXG4gICAgc3ViLCBzdXAge1xyXG4gICAgICAgIGxpbmUtaGVpZ2h0OiBub3JtYWw7XHJcbiAgICAgICAgZm9udC1zaXplOiBzbWFsbGVyO1xyXG4gICAgfVxyXG5cclxuXHJcbiAgICBydWJ5IHtcclxuICAgICAgICBkaXNwbGF5OiBydWJ5O1xyXG4gICAgfVxyXG5cclxuICAgIHJiIHtcclxuICAgICAgICBkaXNwbGF5OiBydWJ5LWJhc2U7XHJcbiAgICAgICAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcclxuICAgIH1cclxuXHJcbiAgICBydCB7XHJcbiAgICAgICAgZGlzcGxheTogcnVieS10ZXh0O1xyXG4gICAgICAgIHdoaXRlLXNwYWNlOiBub3dyYXA7XHJcbiAgICAgICAgZm9udC1zaXplOiA1MCU7XHJcbiAgICAgICAgZm9udC12YXJpYW50LWVhc3QtYXNpYW46IHJ1Ynk7XHJcbiAgICAgICAgdGV4dC1lbXBoYXNpczogbm9uZTtcclxuICAgIH1cclxuXHJcbiAgICByYmMge1xyXG4gICAgICAgIGRpc3BsYXk6IHJ1YnktYmFzZS1jb250YWluZXI7XHJcbiAgICB9XHJcblxyXG4gICAgcnRjIHtcclxuICAgICAgICBkaXNwbGF5OiBydWJ5LXRleHQtY29udGFpbmVyO1xyXG4gICAgfVxyXG5cclxuICAgIHJ1YnksIHJiLCBydCwgcmJjLCBydGMge1xyXG4gICAgICAgIHVuaWNvZGUtYmlkaTogaXNvbGF0ZTtcclxuICAgIH1cclxuXHJcblxyXG4gICAgOmxpbmsge1xyXG4gICAgICAgIGNvbG9yOiAjMDAwMEVFO1xyXG4gICAgfVxyXG5cclxuICAgIDp2aXNpdGVkIHtcclxuICAgICAgICBjb2xvcjogIzU1MUE4QjtcclxuICAgIH1cclxuXHJcbiAgICA6bGluaywgOnZpc2l0ZWQge1xyXG4gICAgICAgIHRleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lO1xyXG4gICAgfVxyXG5cclxuICAgIGE6bGlua1tyZWx+PWhlbHBdLCBhOnZpc2l0ZWRbcmVsfj1oZWxwXSxcclxuICAgIGFyZWE6bGlua1tyZWx+PWhlbHBdLCBhcmVhOnZpc2l0ZWRbcmVsfj1oZWxwXSB7XHJcbiAgICAgICAgY3Vyc29yOiBoZWxwO1xyXG4gICAgfVxyXG5cclxuICAgIDpmb2N1cyB7XHJcbiAgICAgICAgb3V0bGluZTogYXV0bztcclxuICAgIH1cclxuXHJcbiAgICBtYXJrIHtcclxuICAgICAgICBiYWNrZ3JvdW5kOiB5ZWxsb3c7XHJcbiAgICAgICAgY29sb3I6IGJsYWNrO1xyXG4gICAgfVxyXG4gICAgLyogdGhpcyBjb2xvciBpcyBqdXN0IGEgc3VnZ2VzdGlvbiBhbmQgY2FuIGJlIGNoYW5nZWQgYmFzZWQgb24gaW1wbGVtZW50YXRpb24gZmVlZGJhY2sgKi9cclxuICAgIGFiYnJbdGl0bGVdLCBhY3JvbnltW3RpdGxlXSB7XHJcbiAgICAgICAgdGV4dC1kZWNvcmF0aW9uOiBkb3R0ZWQgdW5kZXJsaW5lO1xyXG4gICAgfVxyXG5cclxuICAgIGlucywgdSB7XHJcbiAgICAgICAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7XHJcbiAgICB9XHJcblxyXG4gICAgZGVsLCBzLCBzdHJpa2Uge1xyXG4gICAgICAgIHRleHQtZGVjb3JhdGlvbjogbGluZS10aHJvdWdoO1xyXG4gICAgfVxyXG5cclxuICAgIGJsaW5rIHtcclxuICAgICAgICB0ZXh0LWRlY29yYXRpb246IGJsaW5rO1xyXG4gICAgfVxyXG5cclxuICAgIHE6OmJlZm9yZSB7XHJcbiAgICAgICAgY29udGVudDogb3Blbi1xdW90ZTtcclxuICAgIH1cclxuXHJcbiAgICBxOjphZnRlciB7XHJcbiAgICAgICAgY29udGVudDogY2xvc2UtcXVvdGU7XHJcbiAgICB9XHJcblxyXG4gICAgYnI6OmJlZm9yZSB7XHJcbiAgICAgICAgY29udGVudDogJ1xcQSc7XHJcbiAgICAgICAgd2hpdGUtc3BhY2U6IHByZTtcclxuICAgIH1cclxuICAgIC8qIHRoaXMgYWxzbyBoYXMgYmlkaSBpbXBsaWNhdGlvbnMgKi9cclxuICAgIG5vYnIge1xyXG4gICAgICAgIHdoaXRlLXNwYWNlOiBub3dyYXA7XHJcbiAgICB9XHJcblxyXG4gICAgd2JyIHtcclxuICAgICAgICBjb250ZW50OiAnXFwyMDBCJztcclxuICAgIH1cclxuICAgIC8qIHRoaXMgYWxzbyBoYXMgYmlkaSBpbXBsaWNhdGlvbnMgKi9cclxuICAgIG5vYnIgd2JyIHtcclxuICAgICAgICB3aGl0ZS1zcGFjZTogbm9ybWFsO1xyXG4gICAgfVxyXG5cclxuICAgIGFydGljbGUsIGFzaWRlLCBoMSwgaDIsIGgzLCBoNCwgaDUsIGg2LCBoZ3JvdXAsIG5hdiwgc2VjdGlvbiB7XHJcbiAgICAgICAgZGlzcGxheTogYmxvY2s7XHJcbiAgICB9XHJcblxyXG4gICAgaDEge1xyXG4gICAgICAgIG1hcmdpbi10b3A6IDAuNjdlbTtcclxuICAgICAgICBtYXJnaW4tYm90dG9tOiAwLjY3ZW07XHJcbiAgICAgICAgZm9udC1zaXplOiAyLjAwZW07XHJcbiAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7XHJcbiAgICB9XHJcblxyXG4gICAgaDIge1xyXG4gICAgICAgIG1hcmdpbi10b3A6IDAuODNlbTtcclxuICAgICAgICBtYXJnaW4tYm90dG9tOiAwLjgzZW07XHJcbiAgICAgICAgZm9udC1zaXplOiAxLjUwZW07XHJcbiAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7XHJcbiAgICB9XHJcblxyXG4gICAgaDMge1xyXG4gICAgICAgIG1hcmdpbi10b3A6IDEuMDBlbTtcclxuICAgICAgICBtYXJnaW4tYm90dG9tOiAxLjAwZW07XHJcbiAgICAgICAgZm9udC1zaXplOiAxLjE3ZW07XHJcbiAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7XHJcbiAgICB9XHJcblxyXG4gICAgaDQge1xyXG4gICAgICAgIG1hcmdpbi10b3A6IDEuMzNlbTtcclxuICAgICAgICBtYXJnaW4tYm90dG9tOiAxLjMzZW07XHJcbiAgICAgICAgZm9udC1zaXplOiAxLjAwZW07XHJcbiAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7XHJcbiAgICB9XHJcblxyXG4gICAgaDUge1xyXG4gICAgICAgIG1hcmdpbi10b3A6IDEuNjdlbTtcclxuICAgICAgICBtYXJnaW4tYm90dG9tOiAxLjY3ZW07XHJcbiAgICAgICAgZm9udC1zaXplOiAwLjgzZW07XHJcbiAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7XHJcbiAgICB9XHJcblxyXG4gICAgaDYge1xyXG4gICAgICAgIG1hcmdpbi10b3A6IDIuMzNlbTtcclxuICAgICAgICBtYXJnaW4tYm90dG9tOiAyLjMzZW07XHJcbiAgICAgICAgZm9udC1zaXplOiAwLjY3ZW07XHJcbiAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7XHJcbiAgICB9XHJcblxyXG4gICAgZGlyLCBkZCwgZGwsIGR0LCBvbCwgdWwge1xyXG4gICAgICAgIGRpc3BsYXk6IGJsb2NrO1xyXG4gICAgfVxyXG5cclxuICAgIGxpIHtcclxuICAgICAgICBkaXNwbGF5OiBsaXN0LWl0ZW07XHJcbiAgICB9XHJcblxyXG4gICAgZGlyLCBkbCwgb2wsIHVsIHtcclxuICAgICAgICBtYXJnaW4tdG9wOiAxZW07XHJcbiAgICAgICAgbWFyZ2luLWJvdHRvbTogMWVtO1xyXG4gICAgfVxyXG5cclxuICAgICAgICBkaXIgZGlyLCBkaXIgZGwsIGRpciBvbCwgZGlyIHVsLFxyXG4gICAgICAgIGRsIGRpciwgZGwgZGwsIGRsIG9sLCBkbCB1bCxcclxuICAgICAgICBvbCBkaXIsIG9sIGRsLCBvbCBvbCwgb2wgdWwsXHJcbiAgICAgICAgdWwgZGlyLCB1bCBkbCwgdWwgb2wsIHVsIHVsIHtcclxuICAgICAgICAgICAgbWFyZ2luLXRvcDogMDtcclxuICAgICAgICAgICAgbWFyZ2luLWJvdHRvbTogMDtcclxuICAgICAgICB9XHJcblxyXG4gICAgZGQge1xyXG4gICAgICAgIG1hcmdpbi1sZWZ0OiA0MHB4O1xyXG4gICAgfVxyXG4gICAgLyogTFRSLXNwZWNpZmljOiB1c2UgJ21hcmdpbi1yaWdodCcgZm9yIHJ0bCBlbGVtZW50cyAqL1xyXG4gICAgZGlyLCBvbCwgdWwge1xyXG4gICAgICAgIHBhZGRpbmctbGVmdDogNDBweDtcclxuICAgIH1cclxuICAgIC8qIExUUi1zcGVjaWZpYzogdXNlICdwYWRkaW5nLXJpZ2h0JyBmb3IgcnRsIGVsZW1lbnRzICovXHJcbiAgICBvbCB7XHJcbiAgICAgICAgbGlzdC1zdHlsZS10eXBlOiBkZWNpbWFsO1xyXG4gICAgfVxyXG5cclxuICAgIGRpciwgdWwge1xyXG4gICAgICAgIGxpc3Qtc3R5bGUtdHlwZTogZGlzYztcclxuICAgIH1cclxuXHJcbiAgICAgICAgZGlyIGRpciwgZGlyIHVsLFxyXG4gICAgICAgIG9sIGRpciwgb2wgdWwsXHJcbiAgICAgICAgdWwgZGlyLCB1bCB1bCB7XHJcbiAgICAgICAgICAgIGxpc3Qtc3R5bGUtdHlwZTogY2lyY2xlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGRpciBkaXIgZGlyLCBkaXIgZGlyIHVsLFxyXG4gICAgICAgICAgICBkaXIgb2wgZGlyLCBkaXIgb2wgdWwsXHJcbiAgICAgICAgICAgIGRpciB1bCBkaXIsIGRpciB1bCB1bCxcclxuICAgICAgICAgICAgb2wgZGlyIGRpciwgb2wgZGlyIHVsLFxyXG4gICAgICAgICAgICBvbCBvbCBkaXIsIG9sIG9sIHVsLFxyXG4gICAgICAgICAgICBvbCB1bCBkaXIsIG9sIHVsIHVsLFxyXG4gICAgICAgICAgICB1bCBkaXIgZGlyLCB1bCBkaXIgdWwsXHJcbiAgICAgICAgICAgIHVsIG9sIGRpciwgdWwgb2wgdWwsXHJcbiAgICAgICAgICAgIHVsIHVsIGRpciwgdWwgdWwgdWwge1xyXG4gICAgICAgICAgICAgICAgbGlzdC1zdHlsZS10eXBlOiBzcXVhcmU7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICB0YWJsZSB7XHJcbiAgICAgICAgZGlzcGxheTogdGFibGU7XHJcbiAgICB9XHJcblxyXG4gICAgY2FwdGlvbiB7XHJcbiAgICAgICAgZGlzcGxheTogdGFibGUtY2FwdGlvbjtcclxuICAgIH1cclxuXHJcbiAgICBjb2xncm91cCwgY29sZ3JvdXBbaGlkZGVuXSB7XHJcbiAgICAgICAgZGlzcGxheTogdGFibGUtY29sdW1uLWdyb3VwO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbCwgY29sW2hpZGRlbl0ge1xyXG4gICAgICAgIGRpc3BsYXk6IHRhYmxlLWNvbHVtbjtcclxuICAgIH1cclxuXHJcbiAgICB0aGVhZCwgdGhlYWRbaGlkZGVuXSB7XHJcbiAgICAgICAgZGlzcGxheTogdGFibGUtaGVhZGVyLWdyb3VwO1xyXG4gICAgfVxyXG5cclxuICAgIHRib2R5LCB0Ym9keVtoaWRkZW5dIHtcclxuICAgICAgICBkaXNwbGF5OiB0YWJsZS1yb3ctZ3JvdXA7XHJcbiAgICB9XHJcblxyXG4gICAgdGZvb3QsIHRmb290W2hpZGRlbl0ge1xyXG4gICAgICAgIGRpc3BsYXk6IHRhYmxlLWZvb3Rlci1ncm91cDtcclxuICAgIH1cclxuXHJcbiAgICB0ciwgdHJbaGlkZGVuXSB7XHJcbiAgICAgICAgZGlzcGxheTogdGFibGUtcm93O1xyXG4gICAgfVxyXG5cclxuICAgIHRkLCB0aCwgdGRbaGlkZGVuXSwgdGhbaGlkZGVuXSB7XHJcbiAgICAgICAgZGlzcGxheTogdGFibGUtY2VsbDtcclxuICAgIH1cclxuXHJcbiAgICAgICAgY29sZ3JvdXBbaGlkZGVuXSwgY29sW2hpZGRlbl0sIHRoZWFkW2hpZGRlbl0sIHRib2R5W2hpZGRlbl0sXHJcbiAgICAgICAgdGZvb3RbaGlkZGVuXSwgdHJbaGlkZGVuXSwgdGRbaGlkZGVuXSwgdGhbaGlkZGVuXSB7XHJcbiAgICAgICAgICAgIHZpc2liaWxpdHk6IGNvbGxhcHNlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICB0YWJsZSB7XHJcbiAgICAgICAgYm94LXNpemluZzogYm9yZGVyLWJveDtcclxuICAgICAgICBib3JkZXItc3BhY2luZzogMnB4O1xyXG4gICAgICAgIGJvcmRlci1jb2xsYXBzZTogc2VwYXJhdGU7XHJcbiAgICAgICAgdGV4dC1pbmRlbnQ6IGluaXRpYWw7XHJcbiAgICB9XHJcblxyXG4gICAgdGQsIHRoIHtcclxuICAgICAgICBwYWRkaW5nOiAxcHg7XHJcbiAgICB9XHJcblxyXG4gICAgdGgge1xyXG4gICAgICAgIGZvbnQtd2VpZ2h0OiBib2xkO1xyXG4gICAgfVxyXG5cclxuICAgIHRoZWFkLCB0Ym9keSwgdGZvb3QsIHRhYmxlID4gdHIge1xyXG4gICAgICAgIHZlcnRpY2FsLWFsaWduOiBtaWRkbGU7XHJcbiAgICB9XHJcblxyXG4gICAgdHIsIHRkLCB0aCB7XHJcbiAgICAgICAgdmVydGljYWwtYWxpZ246IGluaGVyaXQ7XHJcbiAgICB9XHJcblxyXG4gICAgdGFibGUsIHRkLCB0aCB7XHJcbiAgICAgICAgYm9yZGVyLWNvbG9yOiBncmF5O1xyXG4gICAgfVxyXG5cclxuICAgIHRoZWFkLCB0Ym9keSwgdGZvb3QsIHRyIHtcclxuICAgICAgICBib3JkZXItY29sb3I6IGluaGVyaXQ7XHJcbiAgICB9XHJcbiAgICAvKnRhYmxlW3J1bGVzPW5vbmUgaV0sIHRhYmxlW3J1bGVzPWdyb3VwcyBpXSwgdGFibGVbcnVsZXM9cm93cyBpXSxcclxudGFibGVbcnVsZXM9Y29scyBpXSwgdGFibGVbcnVsZXM9YWxsIGldLCB0YWJsZVtmcmFtZT12b2lkIGldLFxyXG50YWJsZVtmcmFtZT1hYm92ZSBpXSwgdGFibGVbZnJhbWU9YmVsb3cgaV0sIHRhYmxlW2ZyYW1lPWhzaWRlcyBpXSxcclxudGFibGVbZnJhbWU9bGhzIGldLCB0YWJsZVtmcmFtZT1yaHMgaV0sIHRhYmxlW2ZyYW1lPXZzaWRlcyBpXSxcclxudGFibGVbZnJhbWU9Ym94IGldLCB0YWJsZVtmcmFtZT1ib3JkZXIgaV0sXHJcbnRhYmxlW3J1bGVzPW5vbmUgaV0gPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1ub25lIGldID4gdHIgPiB0aCxcclxudGFibGVbcnVsZXM9Z3JvdXBzIGldID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9Z3JvdXBzIGldID4gdHIgPiB0aCxcclxudGFibGVbcnVsZXM9cm93cyBpXSA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPXJvd3MgaV0gPiB0ciA+IHRoLFxyXG50YWJsZVtydWxlcz1jb2xzIGldID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9Y29scyBpXSA+IHRyID4gdGgsXHJcbnRhYmxlW3J1bGVzPWFsbCBpXSA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWFsbCBpXSA+IHRyID4gdGgsXHJcbnRhYmxlW3J1bGVzPW5vbmUgaV0gPiB0aGVhZCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPW5vbmUgaV0gPiB0aGVhZCA+IHRyID4gdGgsXHJcbnRhYmxlW3J1bGVzPWdyb3VwcyBpXSA+IHRoZWFkID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9Z3JvdXBzIGldID4gdGhlYWQgPiB0ciA+IHRoLFxyXG50YWJsZVtydWxlcz1yb3dzIGldID4gdGhlYWQgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1yb3dzIGldID4gdGhlYWQgPiB0ciA+IHRoLFxyXG50YWJsZVtydWxlcz1jb2xzIGldID4gdGhlYWQgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1jb2xzIGldID4gdGhlYWQgPiB0ciA+IHRoLFxyXG50YWJsZVtydWxlcz1hbGwgaV0gPiB0aGVhZCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWFsbCBpXSA+IHRoZWFkID4gdHIgPiB0aCxcclxudGFibGVbcnVsZXM9bm9uZSBpXSA+IHRib2R5ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9bm9uZSBpXSA+IHRib2R5ID4gdHIgPiB0aCxcclxudGFibGVbcnVsZXM9Z3JvdXBzIGldID4gdGJvZHkgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1ncm91cHMgaV0gPiB0Ym9keSA+IHRyID4gdGgsXHJcbnRhYmxlW3J1bGVzPXJvd3MgaV0gPiB0Ym9keSA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPXJvd3MgaV0gPiB0Ym9keSA+IHRyID4gdGgsXHJcbnRhYmxlW3J1bGVzPWNvbHMgaV0gPiB0Ym9keSA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWNvbHMgaV0gPiB0Ym9keSA+IHRyID4gdGgsXHJcbnRhYmxlW3J1bGVzPWFsbCBpXSA+IHRib2R5ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9YWxsIGldID4gdGJvZHkgPiB0ciA+IHRoLFxyXG50YWJsZVtydWxlcz1ub25lIGldID4gdGZvb3QgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1ub25lIGldID4gdGZvb3QgPiB0ciA+IHRoLFxyXG50YWJsZVtydWxlcz1ncm91cHMgaV0gPiB0Zm9vdCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWdyb3VwcyBpXSA+IHRmb290ID4gdHIgPiB0aCxcclxudGFibGVbcnVsZXM9cm93cyBpXSA+IHRmb290ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9cm93cyBpXSA+IHRmb290ID4gdHIgPiB0aCxcclxudGFibGVbcnVsZXM9Y29scyBpXSA+IHRmb290ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9Y29scyBpXSA+IHRmb290ID4gdHIgPiB0aCxcclxudGFibGVbcnVsZXM9YWxsIGldID4gdGZvb3QgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1hbGwgaV0gPiB0Zm9vdCA+IHRyID4gdGgge1xyXG4gICAgYm9yZGVyLWNvbG9yOiBibGFjaztcclxufSovXHJcbiAgICBpbnB1dCwgc2VsZWN0LCBvcHRpb24sIG9wdGdyb3VwLCBidXR0b24sIHRleHRhcmVhLCBrZXlnZW4ge1xyXG4gICAgICAgIHRleHQtaW5kZW50OiBpbml0aWFsO1xyXG4gICAgfVxyXG5cclxuICAgIHRleHRhcmVhIHtcclxuICAgICAgICB3aGl0ZS1zcGFjZTogcHJlLXdyYXA7XHJcbiAgICB9XHJcblxyXG4gICAgaW5wdXRbdHlwZT1cInJhZGlvXCJdLCBpbnB1dFt0eXBlPVwiY2hlY2tib3hcIl0sIGlucHV0W3R5cGU9XCJyZXNldFwiXSwgaW5wdXRbdHlwZT1cImJ1dHRvblwiXSxcclxuICAgIGlucHV0W3R5cGU9XCJzdWJtaXRcIl0sIHNlbGVjdCwgYnV0dG9uIHtcclxuICAgICAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG4gICAgfVxyXG5cclxuICAgIGlucHV0W3R5cGU9XCJidXR0b25cIl0sIGJ1dHRvbiB7XHJcbiAgICAgICAgcGFkZGluZzogMC4zZW0gMC41ZW07XHJcbiAgICB9XHJcblxyXG4gICAgaHIge1xyXG4gICAgICAgIGNvbG9yOiBncmF5O1xyXG4gICAgICAgIGJvcmRlci1zdHlsZTogaW5zZXQ7XHJcbiAgICAgICAgYm9yZGVyLXdpZHRoOiAxcHg7XHJcbiAgICAgICAgbWFyZ2luOiAwLjVlbSBhdXRvO1xyXG4gICAgfVxyXG5cclxuICAgIGZpZWxkc2V0IHtcclxuICAgICAgICBtYXJnaW4tbGVmdDogMnB4O1xyXG4gICAgICAgIG1hcmdpbi1yaWdodDogMnB4O1xyXG4gICAgICAgIGJvcmRlcjogZ3Jvb3ZlIDJweCBUaHJlZURGYWNlO1xyXG4gICAgICAgIHBhZGRpbmc6IDAuMzVlbSAwLjYyNWVtIDAuNzVlbTtcclxuICAgIH1cclxuXHJcbiAgICBsZWdlbmQge1xyXG4gICAgICAgIHBhZGRpbmctbGVmdDogMnB4O1xyXG4gICAgICAgIHBhZGRpbmctcmlnaHQ6IDJweDtcclxuICAgIH1cclxufVxyXG4iLCLvu79AaW1wb3J0IFwiVmFyaWFibGVzLmxlc3NcIjtcclxuXHJcbi5sYXlvdXQtZWRpdG9yIHtcclxuICAgID4gLmxheW91dC10b29sYm94LXdyYXBwZXIge1xyXG4gICAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcclxuICAgICAgICBtYXJnaW4tbGVmdDogQGNvbnRhaW5lci1wYWRkaW5nO1xyXG4gICAgICAgIHdpZHRoOiAyMjBweDtcclxuICAgICAgICBmbGV4LXNocmluazogMDtcclxuXHJcbiAgICAgICAgPiAubGF5b3V0LXRvb2xib3gge1xyXG4gICAgICAgICAgICBib3JkZXI6IDFweCBzb2xpZCBAZ3JheS1ib3JkZXI7XHJcbiAgICAgICAgICAgIHdpZHRoOiAyMjBweDtcclxuICAgICAgICAgICAgbWluLWhlaWdodDogNDAwcHg7XHJcbiAgICAgICAgICAgIHBhZGRpbmc6IEBjb250YWluZXItcGFkZGluZyAvIDI7XHJcbiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IEBncmF5LWJnO1xyXG5cclxuICAgICAgICAgICAgJi5zdGlja3ktdG9wIHtcclxuICAgICAgICAgICAgICAgIHBvc2l0aW9uOiBmaXhlZDtcclxuICAgICAgICAgICAgICAgIHRvcDogMDtcclxuICAgICAgICAgICAgICAgIG1heC1oZWlnaHQ6IDEwMCU7XHJcbiAgICAgICAgICAgICAgICBvdmVyZmxvdy15OiBhdXRvO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAmLnN0aWNreS1ib3R0b20ge1xyXG4gICAgICAgICAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xyXG4gICAgICAgICAgICAgICAgYm90dG9tOiAwO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAubGF5b3V0LXRvb2xib3gtZ3JvdXAge1xyXG4gICAgICAgICAgICAgICAgbWFyZ2luLXRvcDogQGNvbnRhaW5lci1wYWRkaW5nO1xyXG5cclxuICAgICAgICAgICAgICAgIC5sYXlvdXQtdG9vbGJveC1ncm91cC1oZWFkaW5nIHtcclxuICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBibG9jaztcclxuICAgICAgICAgICAgICAgICAgICBtYXJnaW4tYm90dG9tOiBAY29udGFpbmVyLXBhZGRpbmcgLyAzO1xyXG4gICAgICAgICAgICAgICAgICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZTtcclxuICAgICAgICAgICAgICAgIFxyXG4gICAgICAgICAgICAgICAgICAgICY6YmVmb3JlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB3aWR0aDogMTBweDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgbWFyZ2luLXJpZ2h0OiBAY29udGFpbmVyLXBhZGRpbmcgLyAzO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBmb250OiBub3JtYWwgbm9ybWFsIG5vcm1hbCAxNHB4LzEgRm9udEF3ZXNvbWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRleHQtYWxpZ246IGNlbnRlcjtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29udGVudDogXCJcXGYwZDdcIjtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIFxyXG4gICAgICAgICAgICAgICAgJi5jb2xsYXBzZWQge1xyXG4gICAgICAgICAgICAgICAgICAgIC5sYXlvdXQtdG9vbGJveC1ncm91cC1oZWFkaW5nOmJlZm9yZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRlbnQ6IFwiXFxmMGRhXCI7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAubGF5b3V0LXRvb2xib3gtaXRlbXMge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBub25lO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAubGF5b3V0LXRvb2xib3gtc2VjdGlvbiArIC5sYXlvdXQtdG9vbGJveC1zZWN0aW9uIHtcclxuICAgICAgICAgICAgICAgICAgICBtYXJnaW4tdG9wOiBAY29udGFpbmVyLXBhZGRpbmcgLyAzO1xyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIC5sYXlvdXQtdG9vbGJveC1pdGVtIHtcclxuICAgICAgICAgICAgICAgICAgICBib3JkZXI6IDFweCBzb2xpZCBAZ3JheS1ib3JkZXI7XHJcbiAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogI2ZmZjtcclxuICAgICAgICAgICAgICAgICAgICBwYWRkaW5nOiAoQGNvbnRhaW5lci1wYWRkaW5nIC0gMykgQGNvbnRhaW5lci1wYWRkaW5nO1xyXG4gICAgICAgICAgICAgICAgICAgIGN1cnNvcjogZGVmYXVsdDtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgaSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg6IDE2cHg7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvbnQ6IG5vcm1hbCBub3JtYWwgbm9ybWFsIDE0cHgvMSBGb250QXdlc29tZTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICsgLmxheW91dC10b29sYm94LWl0ZW0ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBtYXJnaW4tdG9wOiBAY29udGFpbmVyLXBhZGRpbmcgLyAzO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICArIC5sYXlvdXQtdG9vbGJveC1ncm91cCB7XHJcbiAgICAgICAgICAgICAgICAgICAgbWFyZ2luLXRvcDogQGNvbnRhaW5lci1wYWRkaW5nIC8gMjtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG4iLCLvu79AaW1wb3J0IFwiVmFyaWFibGVzLmxlc3NcIjtcclxuXHJcbi5sYXlvdXQtZWRpdG9yIHtcclxuICAgIC5sYXlvdXQtcG9wdXAge1xyXG4gICAgICAgIGRpc3BsYXk6IG5vbmU7IC8vIFNob3duIG9ubHkgaW4gYWN0aXZlIG9yIGZvY3VzZWQgc3RhdGVzLlxyXG4gICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgICAgICBtYXJnaW46IDA7XHJcbiAgICAgICAgLW1vei1ib3gtc2hhZG93OiAzcHggM3B4IDExcHggMCByZ2JhKDUwLCA1MCwgNTAsIDAuNSk7XHJcbiAgICAgICAgLXdlYmtpdC1ib3gtc2hhZG93OiAzcHggM3B4IDExcHggMCByZ2JhKDUwLCA1MCwgNTAsIDAuNSk7XHJcbiAgICAgICAgYm94LXNoYWRvdzogM3B4IDNweCAxMXB4IDAgcmdiYSg1MCwgNTAsIDUwLCAwLjUpO1xyXG4gICAgICAgIGJvcmRlcjogMXB4IHNvbGlkIEBncmF5LWJvcmRlcjtcclxuICAgICAgICBwYWRkaW5nOiAycHggMDtcclxuICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjdmN2Y3O1xyXG4gICAgICAgIGxpc3Qtc3R5bGU6IG5vbmU7XHJcbiAgICAgICAgei1pbmRleDogMjA7XHJcbiAgICAgICAgY29sb3I6IEBncmF5LXRleHQ7XHJcbiAgICAgICAgdGV4dC1hbGlnbjogbGVmdDtcclxuICAgICAgICBjdXJzb3I6IGRlZmF1bHQ7XHJcbiAgICAgICAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcclxuICAgICAgICBsaW5lLWhlaWdodDogbm9ybWFsO1xyXG4gICAgICAgIG1pbi13aWR0aDogMzAwcHg7XHJcblxyXG4gICAgICAgICYud2lkZSB7XHJcbiAgICAgICAgICAgIHdpZHRoOiA2MDBweDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC5sYXlvdXQtcG9wdXAtZmxleCB7XHJcbiAgICAgICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgICAgICAgIHBhZGRpbmc6IDJweCA1cHg7XHJcblxyXG4gICAgICAgICAgICAubGF5b3V0LXBvcHVwLWNvbHVtbiArIC5sYXlvdXQtcG9wdXAtY29sdW1uIHtcclxuICAgICAgICAgICAgICAgIG1hcmdpbi1sZWZ0OiA0cHg7XHJcbiAgICAgICAgICAgICAgICBib3JkZXItbGVmdDogMXB4IHNvbGlkIGZhZGUoZ3JheSwgMTUlKTtcclxuICAgICAgICAgICAgICAgIHBhZGRpbmctbGVmdDogNHB4O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAubGF5b3V0LXBvcHVwLWl0ZW0ge1xyXG4gICAgICAgICAgICBwYWRkaW5nOiA0cHggNnB4O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLmxheW91dC1wb3B1cC1sYWJlbCB7XHJcbiAgICAgICAgICAgIGZvbnQtc2l6ZTogMC45ZW07XHJcbiAgICAgICAgICAgIGZvbnQtd2VpZ2h0OiBib2xkO1xyXG4gICAgICAgICAgICBjb2xvcjogQGdyYXktdGV4dDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC5sYXlvdXQtcG9wdXAtYWN0aW9uOmhvdmVyIHtcclxuICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogQGdyYXktYmc7XHJcbiAgICAgICAgICAgIGN1cnNvcjogcG9pbnRlcjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC5sYXlvdXQtcG9wdXAtaW5wdXQge1xyXG4gICAgICAgICAgICBpbnB1dFt0eXBlPSd0ZXh0J10sIHRleHRhcmVhIHtcclxuICAgICAgICAgICAgICAgIHdpZHRoOiAxMDAlO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICA+IGxhYmVsIHtcclxuICAgICAgICAgICAgICAgIGRpc3BsYXk6IGJsb2NrO1xyXG4gICAgICAgICAgICAgICAgZm9udC1zaXplOiAwLjllbTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG4iXX0= */ +/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkVkaXRvci5sZXNzIiwiTGF5b3V0RWRpdG9yLmNzcyIsIkVsZW1lbnQubGVzcyIsIkNvbnRhaW5lci5sZXNzIiwiQ2FudmFzLmxlc3MiLCJSb3cubGVzcyIsIkNvbHVtbi5sZXNzIiwiQ29udGVudC5sZXNzIiwiUmVzZXQubGVzcyIsIlRvb2xib3gubGVzcyIsIlBvcHVwLmxlc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFFQTtFQUNJLHFCQUFBO0VBQUEsY0FBQTtFQUNBLHVCQUFBO01BQUEsK0JBQUE7RUFDQSxtQkFBQTtFQUNBLFVBQUE7Q0NESDtBREhEO0VBT1EscUJBQUE7RUFBQSxjQUFBO0NDRFA7QURORDtFQVVZLGtCQUFBO0NDRFg7QURNRDtFQUNJLHFCQUFBO0VBQUEsY0FBQTtFQUNBLGdCQUFBO0VBQ0EsZ0JBQUE7Q0NKSDtBRENEO0VBTVEsY0FBQTtNQUFBLFVBQUE7RUFDQSxvQkFBQTtFQUNBLDBCQUFBO0VBQ0EsMEJBQUE7Q0NKUDtBRExEO0VBWVksY0FBQTtFQUNBLG9CQUFBO0VBQ0EsaUJBQUE7Q0NKWDtBRFZEO0VBaUJnQix1QkFBQTtDQ0pmO0FEYkQ7RUFzQlksd0JBQUE7RUFDQSxxQkFBQTtFQUNBLG9CQUFBO0NDTlg7QURsQkQ7RUE2QlEsb0JBQUE7Q0NSUDtBRFlEO0VBQ0ksY0FBQTtDQ1ZIO0FEYU87O0VBQ0ksYUFBQTtFQUNBLGVBQUE7Q0NWWDtBRGFPO0VBQ0ksWUFBQTtDQ1hYO0FEQ0Q7O0VBY1ksZ0JBQUE7Q0NYWDtBREhEO0VBa0JZLHVCQUFBO0VBQ0EsWUFBQTtFQUNBLFdBQUE7Q0NaWDtBRGNXO0VBQ0ksb0JBQUE7RUFDQSxZQUFBO0NDWmY7QURaRDtFQTZCWSxnQkFBQTtDQ2RYO0FEZkQ7RUFrQ1EsbUJBQUE7RUFDQSwwQkFBQTtFQUNBLGlCQUFBO0VBQ0EsdUJBQUE7Q0NoQlA7QURyQkQ7RUF5Q1EscUJBQUE7RUFDQSxtQkFBQTtDQ2pCUDtBRHpCRDtFQThDUSxvQkFBQTtDQ2xCUDs7QUM1RUQ7RUFF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VEQ7O0VDQVEsVUFBQTtFQUNBLFdBQUE7RUFDQSx3QkFBQTtDUHlUUDtBTTNURDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7RUNPUSxlQUFBO0NQc1ZQO0FNN1ZEOzs7Ozs7Ozs7Ozs7OztFQ1dRLGdCQUFBO0VBQ0EsbUJBQUE7Q1BrV1A7QU05V0Q7Ozs7RUNnQlEsa0JBQUE7RUFDQSxtQkFBQTtDUG9XUDtBTXJYRDs7RUNxQlEsbUJBQUE7Q1BvV1A7QU16WEQ7Ozs7Ozs7O0VDeUJRLHVCQUFBO0VBQ0EsaUJBQUE7Q1AwV1A7QU1wWUQ7Ozs7Ozs7Ozs7RUM4QlEsbUJBQUE7Q1BrWFA7QU1oWkQ7Ozs7RUNrQ1Esb0JBQUE7Q1BvWFA7QU10WkQ7Ozs7Ozs7O0VDc0NRLHVCQUFBO0NQMFhQO0FNaGFEOztFQzBDUSxrQkFBQTtDUDBYUDtBTXBhRDs7RUM4Q1EsbUJBQUE7Q1AwWFA7QU14YUQ7O0VDa0RRLG9CQUFBO0NQMFhQO0FNNWFEOztFQ3NEUSxzQkFBQTtDUDBYUDtBTWhiRDs7OztFQzBEUSxvQkFBQTtFQUNBLG1CQUFBO0NQNFhQO0FNdmJEOztFQ2dFUSxjQUFBO0NQMlhQO0FNM2JEOztFQ29FUSxtQkFBQTtFQUNBLG9CQUFBO0NQMlhQO0FNaGNEOztFQ3lFUSxtQkFBQTtFQUNBLG9CQUFBO0VBQ0EsZUFBQTtFQUNBLDhCQUFBO0VBQ0Esb0JBQUE7Q1AyWFA7QU14Y0Q7O0VDaUZRLDZCQUFBO0NQMlhQO0FNNWNEOztFQ3FGUSw2QkFBQTtDUDJYUDtBTWhkRDs7Ozs7Ozs7OztFQ3lGUSxzQkFBQTtDUG1ZUDtBTTVkRDs7RUM4RlEsZUFBQTtDUGtZUDtBTWhlRDs7RUNrR1EsZUFBQTtDUGtZUDtBTXBlRDs7OztFQ3NHUSwyQkFBQTtDUG9ZUDtBTTFlRDs7Ozs7Ozs7RUMyR1EsYUFBQTtDUHlZUDtBTXBmRDs7RUMrR1EsY0FBQTtDUHlZUDtBTXhmRDs7RUNtSFEsbUJBQUE7RUFDQSxhQUFBO0NQeVlQO0FNN2ZEOzs7O0VDd0hRLGtDQUFBO0NQMllQO0FNbmdCRDs7OztFQzRIUSwyQkFBQTtDUDZZUDtBTXpnQkQ7Ozs7OztFQ2dJUSw4QkFBQTtDUGlaUDtBTWpoQkQ7O0VDb0lRLHVCQUFBO0NQaVpQO0FNcmhCRDs7RUN3SVEsb0JBQUE7Q1BpWlA7QU16aEJEOztFQzRJUSxxQkFBQTtDUGlaUDtBTTdoQkQ7O0VDZ0pRLGNBQUE7RUFDQSxpQkFBQTtDUGlaUDtBTWxpQkQ7O0VDcUpRLG9CQUFBO0NQaVpQO0FNdGlCRDs7RUN5SlEsaUJBQUE7Q1BpWlA7QU0xaUJEOztFQzZKUSxvQkFBQTtDUGlaUDtBTTlpQkQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7RUNpS1EsZUFBQTtDUHFhUDtBTXRrQkQ7O0VDcUtRLG1CQUFBO0VBQ0Esc0JBQUE7RUFDQSxrQkFBQTtFQUNBLGtCQUFBO0NQcWFQO0FNN2tCRDs7RUM0S1EsbUJBQUE7RUFDQSxzQkFBQTtFQUNBLGtCQUFBO0VBQ0Esa0JBQUE7Q1BxYVA7QU1wbEJEOztFQ21MUSxtQkFBQTtFQUNBLHNCQUFBO0VBQ0Esa0JBQUE7RUFDQSxrQkFBQTtDUHFhUDtBTTNsQkQ7O0VDMExRLG1CQUFBO0VBQ0Esc0JBQUE7RUFDQSxrQkFBQTtFQUNBLGtCQUFBO0NQcWFQO0FNbG1CRDs7RUNpTVEsbUJBQUE7RUFDQSxzQkFBQTtFQUNBLGtCQUFBO0VBQ0Esa0JBQUE7Q1BxYVA7QU16bUJEOztFQ3dNUSxtQkFBQTtFQUNBLHNCQUFBO0VBQ0Esa0JBQUE7RUFDQSxrQkFBQTtDUHFhUDtBTWhuQkQ7Ozs7Ozs7Ozs7OztFQytNUSxlQUFBO0NQK2FQO0FNOW5CRDs7RUNtTlEsbUJBQUE7Q1ArYVA7QU1sb0JEOzs7Ozs7OztFQ3VOUSxnQkFBQTtFQUNBLG1CQUFBO0NQcWJQO0FNN29CRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7RUMrTlksY0FBQTtFQUNBLGlCQUFBO0NQZ2RYO0FNaHJCRDs7RUNvT1Esa0JBQUE7Q1BnZFA7QU1wckJEOzs7Ozs7RUN3T1EsbUJBQUE7Q1BvZFA7QU01ckJEOztFQzRPUSx5QkFBQTtDUG9kUDtBTWhzQkQ7Ozs7RUNnUFEsc0JBQUE7Q1BzZFA7QU10c0JEOzs7Ozs7Ozs7Ozs7RUNzUFksd0JBQUE7Q1A4ZFg7QU1wdEJEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7RUNrUWdCLHdCQUFBO0NQd2ZmO0FNMXZCRDs7RUNzUVEsZUFBQTtDUHdmUDtBTTl2QkQ7O0VDMFFRLHVCQUFBO0NQd2ZQO0FNbHdCRDs7OztFQzhRUSw0QkFBQTtDUDBmUDtBTXh3QkQ7Ozs7RUNrUlEsc0JBQUE7Q1A0ZlA7QU05d0JEOzs7O0VDc1JRLDRCQUFBO0NQOGZQO0FNcHhCRDs7OztFQzBSUSx5QkFBQTtDUGdnQlA7QU0xeEJEOzs7O0VDOFJRLDRCQUFBO0NQa2dCUDtBTWh5QkQ7Ozs7RUNrU1EsbUJBQUE7Q1BvZ0JQO0FNdHlCRDs7Ozs7Ozs7RUNzU1Esb0JBQUE7Q1AwZ0JQO0FNaHpCRDs7Ozs7Ozs7Ozs7Ozs7OztFQzJTWSxxQkFBQTtDUHVoQlg7QU1sMEJEOztFQytTUSx1QkFBQTtFQUNBLG9CQUFBO0VBQ0EsMEJBQUE7RUFDQSxxQkFBQTtDUHVoQlA7QU16MEJEOzs7O0VDc1RRLGFBQUE7Q1B5aEJQO0FNLzBCRDs7RUMwVFEsa0JBQUE7Q1B5aEJQO0FNbjFCRDs7Ozs7Ozs7RUM4VFEsdUJBQUE7Q1AraEJQO0FNNzFCRDs7Ozs7O0VDa1VRLHdCQUFBO0NQbWlCUDtBTXIyQkQ7Ozs7OztFQ3NVUSxtQkFBQTtDUHVpQlA7QU03MkJEOzs7Ozs7OztFQzBVUSxzQkFBQTtDUDZpQlA7QU12M0JEOzs7Ozs7Ozs7Ozs7OztFQ3dXUSxxQkFBQTtDUCtoQlA7QU12NEJEOztFQzRXUSxzQkFBQTtDUCtoQlA7QU0zNEJEOzs7Ozs7Ozs7Ozs7OztFQ2lYUSx1QkFBQTtDUDBpQlA7QU0zNUJEOzs7O0VDcVhRLHFCQUFBO0NQNGlCUDtBTWo2QkQ7O0VDeVhRLFlBQUE7RUFDQSxvQkFBQTtFQUNBLGtCQUFBO0VBQ0EsbUJBQUE7Q1A0aUJQO0FNeDZCRDs7RUNnWVEsaUJBQUE7RUFDQSxrQkFBQTtFQUNBLDhCQUFBO0VBQ0EsK0JBQUE7Q1A0aUJQO0FNLzZCRDs7RUN1WVEsa0JBQUE7RUFDQSxtQkFBQTtDUDRpQlA7QU1wN0JEOztFQWVvQix5QkFBQTtDTnk2Qm5CO0FNeDdCRDs7RUFtQm9CLDRCQUFBO0NOeTZCbkI7QU1wNkJPOzs7O0VBRVEsZUFBQTtFQUNBLFlBQUE7RUFDQSxnQkFBQTtFQUNBLGFBQUE7Q053NkJmO0FNcjhCRDs7RUFtQ1EsZUFBQTtFQUNBLFlBQUE7RUFDQSxnQkFBQTtFQUNBLGFBQUE7Q05zNkJQOztBUTc4QkQ7RUFFUSwwQkFBQTtFQUNBLHVCQUFBO0VBQ0Esa0JBQUE7RUFDQSxnQkFBQTtFQUNBLHNCQUFBO0NSKzhCUDtBUXI5QkQ7RUFTWSxzQkFBQTtFQUNBLFlBQUE7RUFDQSw4Q0FBQTtDUis4Qlg7QVExOUJEO0VBZVksZ0JBQUE7Q1I4OEJYO0FRejhCRDtFQUVRLGlCQUFBO0VBQ0EsU0FBQTtFQUNBLG1CQUFBO0VBQ0EsYUFBQTtFQUNBLGlCQUFBO0VBQ0Esc0JBQUE7RUFDQSxrQkFBQTtFQUNBLGlCQUFBO0VBQ0EsYUFBQTtDUjA4QlA7QVFwOUJEO0VBYVksMEJBQUE7RUFDQSxhQUFBO0VBQ0EsMEJBQUE7Q1IwOEJYO0FRejlCRDtFQW1Cb0IsZUFBQTtFQUNBLG1CQUFBO0VBQ0Esc0JBQUE7Q1J5OEJuQjtBUXY4Qm1CO0VBQ0ksc0JBQUE7RUFDQSxZQUFBO0VBQ0Esa0JBQUE7RUFDQSw4Q0FBQTtFQUNBLG1CQUFBO0VBQ0EsaUJBQUE7Q1J5OEJ2QjtBUXI4QmU7RUFFUSxpQkFBQTtDUnM4QnZCO0FReDhCZTtFQU1RLGNBQUE7Q1JxOEJ2QjtBUTUrQkQ7RUE0Q29CLGdCQUFBO0NSbThCbkI7QVEvK0JEO0VBZ0RvQiwwQkFBQTtFQUNBLHVCQUFBO0VBQ0Esa0JBQUE7RUFDQSxnQkFBQTtDUms4Qm5CO0FRci9CRDtFQXNEd0Isc0JBQUE7RUFDQSxZQUFBO0VBQ0EsOENBQUE7Q1JrOEJ2QjtBUTEvQkQ7RUE0RHdCLGdCQUFBO0NSaThCdkI7QVE3L0JEO0VBaUVvQixnQkFBQTtDUis3Qm5COztBU3BoQ0Q7RUFFUSxjQUFBO0VBQ0EsbUJBQUE7RUFDQSxVQUFBO0VBR0EsaURBQUE7RUFDQSwwQkFBQTtFQUNBLGVBQUE7RUFDQSwwQkFBQTtFQUNBLGlCQUFBO0VBQ0EsWUFBQTtFQUNBLGVBQUE7RUFDQSxpQkFBQTtFQUNBLGdCQUFBO0VBQ0Esb0JBQUE7RUFDQSxvQkFBQTtFQUNBLGlCQUFBO0NUc2hDUDtBU3BoQ087RUFDSSxhQUFBO0NUc2hDWDtBUzNpQ0Q7RUF5QlkscUJBQUE7RUFBQSxjQUFBO0VBQ0EsaUJBQUE7Q1RxaENYO0FTL2lDRDtFQTZCZ0IsaUJBQUE7RUFDQSxpREFBQTtFQUNBLGtCQUFBO0NUcWhDZjtBU3BqQ0Q7RUFvQ1ksaUJBQUE7Q1RtaENYO0FTdmpDRDtFQXdDWSxpQkFBQTtFQUNBLGtCQUFBO0VBQ0EsZUFBQTtDVGtoQ1g7QVM1akNEO0VBOENZLDBCQUFBO0VBQ0EsZ0JBQUE7Q1RpaENYO0FTaGtDRDs7RUFvRGdCLFlBQUE7Q1RnaENmO0FTcGtDRDtFQXdEZ0IsZUFBQTtFQUNBLGlCQUFBO0NUK2dDZiIsImZpbGUiOiJMYXlvdXRFZGl0b3IuY3NzIiwic291cmNlc0NvbnRlbnQiOlsi77u/QGltcG9ydCBcIlZhcmlhYmxlcy5sZXNzXCI7XHJcblxyXG4ubGF5b3V0LWVkaXRvci10b29sYmFyIHtcclxuICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgICB0b3A6IDEwcHg7XHJcblxyXG4gICAgLmxheW91dC1lZGl0b3ItdG9vbGJhci1ncm91cCB7XHJcbiAgICAgICAgZGlzcGxheTogZmxleDtcclxuXHJcbiAgICAgICAgPiBsaSArIGxpIHtcclxuICAgICAgICAgICAgbWFyZ2luLWxlZnQ6IDEycHg7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcblxyXG4ubGF5b3V0LWVkaXRvciB7XHJcbiAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgbWFyZ2luLXRvcDogMWVtO1xyXG4gICAgZm9udC1zaXplOiBAZm9udC1zaXplO1xyXG5cclxuICAgID4gLmxheW91dC1jYW52YXMtd3JhcHBlciB7XHJcbiAgICAgICAgZmxleDogMSAxO1xyXG4gICAgICAgIGhlaWdodDogZml0LWNvbnRlbnQ7XHJcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogQGdyYXktYmc7XHJcbiAgICAgICAgYm9yZGVyOiAxcHggc29saWQgQGdyYXktYm9yZGVyO1xyXG5cclxuICAgICAgICA+IC5sYXlvdXQtdG9vbGJhci1jb250YWluZXIge1xyXG4gICAgICAgICAgICBkaXNwbGF5OiBub25lO1xyXG4gICAgICAgICAgICBtYXJnaW46IEBjb250YWluZXItcGFkZGluZyBAY29udGFpbmVyLXBhZGRpbmcgMDtcclxuICAgICAgICAgICAgbWluLWhlaWdodDogNzFweDtcclxuXHJcbiAgICAgICAgICAgID4gLm1jZS1wYW5lbCB7XHJcbiAgICAgICAgICAgICAgICB3aWR0aDogMTAwJSAhaW1wb3J0YW50O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwID4gLmxheW91dC1wbGFjZWhvbGRlciB7XHJcbiAgICAgICAgICAgIGJvcmRlcjogMXB4IGRhc2hlZCAjY2NjO1xyXG4gICAgICAgICAgICBwYWRkaW5nOiAwLjJlbSAwLjRlbTtcclxuICAgICAgICAgICAgYmFja2dyb3VuZDogI2U4ZThlODtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLmxheW91dC1zbmlwcGV0IHtcclxuICAgICAgICBiYWNrZ3JvdW5kOiAjZThlOGU4O1xyXG4gICAgfVxyXG59XHJcblxyXG4ubGF5b3V0LWVkaXRvci1oZWxwLWRpYWxvZyB7XHJcbiAgICBkaXNwbGF5OiBub25lO1xyXG5cclxuICAgIC5oZWxwLXJvdyB7XHJcbiAgICAgICAgJjpiZWZvcmUsICY6YWZ0ZXIge1xyXG4gICAgICAgICAgICBjb250ZW50OiBcIiBcIjsgLy8gMVxyXG4gICAgICAgICAgICBkaXNwbGF5OiB0YWJsZTsgLy8gMlxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgJjphZnRlciB7XHJcbiAgICAgICAgICAgIGNsZWFyOiBib3RoO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgPiAuaGVscC1jb2x1bW4tZnVsbCwgPiAuaGVscC1jb2x1bW4taGFsZiB7XHJcbiAgICAgICAgICAgIG1hcmdpbjogMC41ZW0gMDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgID4gLmhlbHAtY29sdW1uLWhhbGYge1xyXG4gICAgICAgICAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG4gICAgICAgICAgICBmbG9hdDogbGVmdDtcclxuICAgICAgICAgICAgd2lkdGg6IDUwJTtcclxuXHJcbiAgICAgICAgICAgICY6bnRoLWNoaWxkKDJuKSB7XHJcbiAgICAgICAgICAgICAgICBwYWRkaW5nLXJpZ2h0OiAxMHB4O1xyXG4gICAgICAgICAgICAgICAgY2xlYXI6IGxlZnQ7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICsgLmhlbHAtcm93IHtcclxuICAgICAgICAgICAgbWFyZ2luLXRvcDogMWVtO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBjb2RlIHtcclxuICAgICAgICBib3JkZXItcmFkaXVzOiA0cHg7XHJcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogI2YzZjRmNTtcclxuICAgICAgICBwYWRkaW5nOiAycHggNHB4O1xyXG4gICAgICAgIGZvbnQtZmFtaWx5OiBtb25vc3BhY2U7XHJcbiAgICB9XHJcblxyXG4gICAgcCB7XHJcbiAgICAgICAgbWFyZ2luLWJvdHRvbTogMC41ZW07XHJcbiAgICAgICAgbGluZS1oZWlnaHQ6IDEuNmVtO1xyXG4gICAgfVxyXG5cclxuICAgIHRhYmxlID4gdGJvZHkgPiB0ciA+IHRkOmZpcnN0LWNoaWxkIHtcclxuICAgICAgICBwYWRkaW5nLXJpZ2h0OiAxMHB4O1xyXG4gICAgfVxyXG59XHJcbiIsIi5sYXlvdXQtZWRpdG9yLXRvb2xiYXIge1xuICBkaXNwbGF5OiBmbGV4O1xuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgdG9wOiAxMHB4O1xufVxuLmxheW91dC1lZGl0b3ItdG9vbGJhciAubGF5b3V0LWVkaXRvci10b29sYmFyLWdyb3VwIHtcbiAgZGlzcGxheTogZmxleDtcbn1cbi5sYXlvdXQtZWRpdG9yLXRvb2xiYXIgLmxheW91dC1lZGl0b3ItdG9vbGJhci1ncm91cCA+IGxpICsgbGkge1xuICBtYXJnaW4tbGVmdDogMTJweDtcbn1cbi5sYXlvdXQtZWRpdG9yIHtcbiAgZGlzcGxheTogZmxleDtcbiAgbWFyZ2luLXRvcDogMWVtO1xuICBmb250LXNpemU6IDE0cHg7XG59XG4ubGF5b3V0LWVkaXRvciA+IC5sYXlvdXQtY2FudmFzLXdyYXBwZXIge1xuICBmbGV4OiAxIDE7XG4gIGhlaWdodDogZml0LWNvbnRlbnQ7XG4gIGJhY2tncm91bmQtY29sb3I6ICNmM2Y0ZjU7XG4gIGJvcmRlcjogMXB4IHNvbGlkICNlNGU1ZTY7XG59XG4ubGF5b3V0LWVkaXRvciA+IC5sYXlvdXQtY2FudmFzLXdyYXBwZXIgPiAubGF5b3V0LXRvb2xiYXItY29udGFpbmVyIHtcbiAgZGlzcGxheTogbm9uZTtcbiAgbWFyZ2luOiAxMnB4IDEycHggMDtcbiAgbWluLWhlaWdodDogNzFweDtcbn1cbi5sYXlvdXQtZWRpdG9yID4gLmxheW91dC1jYW52YXMtd3JhcHBlciA+IC5sYXlvdXQtdG9vbGJhci1jb250YWluZXIgPiAubWNlLXBhbmVsIHtcbiAgd2lkdGg6IDEwMCUgIWltcG9ydGFudDtcbn1cbi5sYXlvdXQtZWRpdG9yID4gLmxheW91dC1jYW52YXMtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwID4gLmxheW91dC1wbGFjZWhvbGRlciB7XG4gIGJvcmRlcjogMXB4IGRhc2hlZCAjY2NjO1xuICBwYWRkaW5nOiAwLjJlbSAwLjRlbTtcbiAgYmFja2dyb3VuZDogI2U4ZThlODtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtc25pcHBldCB7XG4gIGJhY2tncm91bmQ6ICNlOGU4ZTg7XG59XG4ubGF5b3V0LWVkaXRvci1oZWxwLWRpYWxvZyB7XG4gIGRpc3BsYXk6IG5vbmU7XG59XG4ubGF5b3V0LWVkaXRvci1oZWxwLWRpYWxvZyAuaGVscC1yb3c6YmVmb3JlLFxuLmxheW91dC1lZGl0b3ItaGVscC1kaWFsb2cgLmhlbHAtcm93OmFmdGVyIHtcbiAgY29udGVudDogXCIgXCI7XG4gIGRpc3BsYXk6IHRhYmxlO1xufVxuLmxheW91dC1lZGl0b3ItaGVscC1kaWFsb2cgLmhlbHAtcm93OmFmdGVyIHtcbiAgY2xlYXI6IGJvdGg7XG59XG4ubGF5b3V0LWVkaXRvci1oZWxwLWRpYWxvZyAuaGVscC1yb3cgPiAuaGVscC1jb2x1bW4tZnVsbCxcbi5sYXlvdXQtZWRpdG9yLWhlbHAtZGlhbG9nIC5oZWxwLXJvdyA+IC5oZWxwLWNvbHVtbi1oYWxmIHtcbiAgbWFyZ2luOiAwLjVlbSAwO1xufVxuLmxheW91dC1lZGl0b3ItaGVscC1kaWFsb2cgLmhlbHAtcm93ID4gLmhlbHAtY29sdW1uLWhhbGYge1xuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xuICBmbG9hdDogbGVmdDtcbiAgd2lkdGg6IDUwJTtcbn1cbi5sYXlvdXQtZWRpdG9yLWhlbHAtZGlhbG9nIC5oZWxwLXJvdyA+IC5oZWxwLWNvbHVtbi1oYWxmOm50aC1jaGlsZCgybikge1xuICBwYWRkaW5nLXJpZ2h0OiAxMHB4O1xuICBjbGVhcjogbGVmdDtcbn1cbi5sYXlvdXQtZWRpdG9yLWhlbHAtZGlhbG9nIC5oZWxwLXJvdyArIC5oZWxwLXJvdyB7XG4gIG1hcmdpbi10b3A6IDFlbTtcbn1cbi5sYXlvdXQtZWRpdG9yLWhlbHAtZGlhbG9nIGNvZGUge1xuICBib3JkZXItcmFkaXVzOiA0cHg7XG4gIGJhY2tncm91bmQtY29sb3I6ICNmM2Y0ZjU7XG4gIHBhZGRpbmc6IDJweCA0cHg7XG4gIGZvbnQtZmFtaWx5OiBtb25vc3BhY2U7XG59XG4ubGF5b3V0LWVkaXRvci1oZWxwLWRpYWxvZyBwIHtcbiAgbWFyZ2luLWJvdHRvbTogMC41ZW07XG4gIGxpbmUtaGVpZ2h0OiAxLjZlbTtcbn1cbi5sYXlvdXQtZWRpdG9yLWhlbHAtZGlhbG9nIHRhYmxlID4gdGJvZHkgPiB0ciA+IHRkOmZpcnN0LWNoaWxkIHtcbiAgcGFkZGluZy1yaWdodDogMTBweDtcbn1cblxuLmxheW91dC1lZGl0b3IgLmxheW91dC1lbGVtZW50IHtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBtYXJnaW4tdG9wOiAwO1xuICBtYXJnaW4tcmlnaHQ6IDA7XG4gIG1hcmdpbi1ib3R0b206IDA7XG4gIHBhZGRpbmc6IDA7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWVsZW1lbnQ6bm90KC5sYXlvdXQtY29sdW1uKSB7XG4gIG1hcmdpbi1sZWZ0OiAwO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1lbGVtZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LXBhbmVsIHtcbiAgZGlzcGxheTogbm9uZTtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICBtYXJnaW46IDA7XG4gIHotaW5kZXg6IDIwO1xuICBoZWlnaHQ6IDI1cHg7XG4gIHBhZGRpbmc6IDAgNnB4O1xuICBsaXN0LXN0eWxlOiBub25lO1xuICB3aGl0ZS1zcGFjZTogbm93cmFwO1xuICBsaW5lLWhlaWdodDogMjVweDtcbiAgdmVydGljYWwtYWxpZ246IG1pZGRsZTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtZWxlbWVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1wYW5lbCA+IC5sYXlvdXQtcGFuZWwtaXRlbSB7XG4gIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgaGVpZ2h0OiAyNXB4O1xuICBwYWRkaW5nOiAxcHggNnB4IDA7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWVsZW1lbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtcGFuZWwgPiAubGF5b3V0LXBhbmVsLWxhYmVsIHtcbiAgZm9udC1zaXplOiAxM3B4O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1lbGVtZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LXBhbmVsID4gLmxheW91dC1wYW5lbC1hY3Rpb24ge1xuICBkaXNwbGF5OiBub25lO1xuICB3aWR0aDogMjhweDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICB0ZXh0LWFsaWduOiBjZW50ZXI7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWVsZW1lbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtcGFuZWwtbWFpbiB7XG4gIHRvcDogLTI3cHg7XG4gIGxlZnQ6IC0ycHg7XG59XG4ubGF5b3V0LWVkaXRvciBsaS5sYXlvdXQtZWxlbWVudCB7XG4gIGxpc3Qtc3R5bGU6IG5vbmU7XG59XG4ubGF5b3V0LWVkaXRvcjpub3QoLmxheW91dC1lZGl0b3ItZHJhZ2dpbmcpIC5sYXlvdXQtZWxlbWVudC1hY3RpdmUsXG4ubGF5b3V0LWVkaXRvcjpub3QoLmxheW91dC1lZGl0b3ItZHJhZ2dpbmcpIC5sYXlvdXQtZWxlbWVudC1mb2N1c2VkIHtcbiAgYm9yZGVyLXdpZHRoOiAycHg7XG4gIGJvcmRlci1zdHlsZTogc29saWQ7XG59XG4ubGF5b3V0LWVkaXRvcjpub3QoLmxheW91dC1lZGl0b3ItZHJhZ2dpbmcpIC5sYXlvdXQtZWxlbWVudC1hY3RpdmUgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlcixcbi5sYXlvdXQtZWRpdG9yOm5vdCgubGF5b3V0LWVkaXRvci1kcmFnZ2luZykgLmxheW91dC1lbGVtZW50LWZvY3VzZWQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciB7XG4gIG1hcmdpbjogLTJweDtcbn1cbi5sYXlvdXQtZWRpdG9yOm5vdCgubGF5b3V0LWVkaXRvci1kcmFnZ2luZykgLmxheW91dC1lbGVtZW50LWFjdGl2ZSB7XG4gIGJvcmRlci1jb2xvcjogcmdiYSgxMDQsIDEwNCwgMTA0LCAwLjEpO1xufVxuLmxheW91dC1lZGl0b3I6bm90KC5sYXlvdXQtZWRpdG9yLWRyYWdnaW5nKSAubGF5b3V0LWVsZW1lbnQtYWN0aXZlID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LXBhbmVsLW1haW4ge1xuICBkaXNwbGF5OiBibG9jaztcbiAgei1pbmRleDogMzA7XG4gIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMTA0LCAxMDQsIDEwNCwgMC4xKTtcbn1cbi5sYXlvdXQtZWRpdG9yOm5vdCgubGF5b3V0LWVkaXRvci1kcmFnZ2luZykgLmxheW91dC1lbGVtZW50LWZvY3VzZWQge1xuICBib3JkZXItY29sb3I6ICM2NDg3MjE7XG59XG4ubGF5b3V0LWVkaXRvcjpub3QoLmxheW91dC1lZGl0b3ItZHJhZ2dpbmcpIC5sYXlvdXQtZWxlbWVudC1mb2N1c2VkID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LXBhbmVsIHtcbiAgZGlzcGxheTogYmxvY2s7XG4gIGJhY2tncm91bmQtY29sb3I6ICM2NDg3MjE7XG4gIGNvbG9yOiAjZmVmZWZlO1xufVxuLmxheW91dC1lZGl0b3I6bm90KC5sYXlvdXQtZWRpdG9yLWRyYWdnaW5nKSAubGF5b3V0LWVsZW1lbnQtZm9jdXNlZCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1wYW5lbCA+IC5sYXlvdXQtcGFuZWwtYWN0aW9uIHtcbiAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xufVxuLmxheW91dC1lZGl0b3I6bm90KC5sYXlvdXQtZWRpdG9yLWRyYWdnaW5nKSAubGF5b3V0LWVsZW1lbnQtZm9jdXNlZCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1wYW5lbCA+IC5sYXlvdXQtcGFuZWwtYWN0aW9uOmhvdmVyIHtcbiAgYmFja2dyb3VuZC1jb2xvcjogIzgyYjAyYjtcbn1cbi5sYXlvdXQtZWRpdG9yOm5vdCgubGF5b3V0LWVkaXRvci1kcmFnZ2luZykgLmxheW91dC1lbGVtZW50LWZvY3VzZWQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtcGFuZWwgPiAubGF5b3V0LXBhbmVsLWFjdGlvbi5kaXNhYmxlZCB7XG4gIGN1cnNvcjogZGVmYXVsdDtcbiAgY29sb3I6IHJnYmEoMjU0LCAyNTQsIDI1NCwgMC40KTtcbn1cbi5sYXlvdXQtZWRpdG9yOm5vdCgubGF5b3V0LWVkaXRvci1kcmFnZ2luZykgLmxheW91dC1lbGVtZW50LWZvY3VzZWQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtcGFuZWwgPiAubGF5b3V0LXBhbmVsLWFjdGlvbi5kaXNhYmxlZDpob3ZlciB7XG4gIGJhY2tncm91bmQtY29sb3I6ICM2NDg3MjE7XG59XG4ubGF5b3V0LWVkaXRvcjpub3QoLmxheW91dC1lZGl0b3ItZHJhZ2dpbmcpIC5sYXlvdXQtZWxlbWVudC1mb2N1c2VkID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LXBhbmVsID4gLmxheW91dC1wYW5lbC1hY3Rpb24uYWN0aXZlIHtcbiAgY29sb3I6ICNkZWZmNDI7XG4gIGJhY2tncm91bmQtY29sb3I6ICM3MzliMjY7XG59XG4ubGF5b3V0LWVkaXRvcjpub3QoLmxheW91dC1lZGl0b3ItZHJhZ2dpbmcpIC5sYXlvdXQtZWxlbWVudC1mb2N1c2VkID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LXBhbmVsID4gLmxheW91dC1wYW5lbC1hY3Rpb24uYWN0aXZlOmhvdmVyIHtcbiAgYmFja2dyb3VuZC1jb2xvcjogIzgyYjAyYjtcbn1cbi5sYXlvdXQtZWRpdG9yOm5vdCgubGF5b3V0LWVkaXRvci1kcmFnZ2luZykgLmxheW91dC1lbGVtZW50LXNlbGVjdGVkIHtcbiAgYmFja2dyb3VuZC1jb2xvcjogcmdiYSgxMDAsIDEzNSwgMzMsIDAuMDgpO1xufVxuLmxheW91dC1lZGl0b3IgLnVpLXNvcnRhYmxlLXBsYWNlaG9sZGVyIHtcbiAgZGlzcGxheTogbm9uZTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtZWxlbWVudC1kcm9wdGFyZ2V0IHtcbiAgYm94LXNoYWRvdzogaW5zZXQgMCAwIDEycHggNnB4IHJnYmEoMTAwLCAxMzUsIDMzLCAwLjUpO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1lbGVtZW50LWRyb3B0YXJnZXQgLnVpLXNvcnRhYmxlLXBsYWNlaG9sZGVyIHtcbiAgZGlzcGxheTogYmxvY2s7XG4gIHZpc2liaWxpdHk6IHZpc2libGUgIWltcG9ydGFudDtcbiAgbWluLWhlaWdodDogNzhweDtcbiAgYm9yZGVyOiAycHggZGFzaGVkICM2NDg3MjEgIWltcG9ydGFudDtcbiAgYmFja2dyb3VuZC1jb2xvcjogcmdiYSgxMDAsIDEzNSwgMzMsIDAuMTYpO1xufVxuLmxheW91dC1lZGl0b3IgLm1lZGlhLXRodW1ibmFpbCBpbWcge1xuICBtYXgtd2lkdGg6IDEwMCU7XG4gIG1heC1oZWlnaHQ6IDEwMCU7XG59XG5cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGFpbmVyID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNvbnRhaW5lci1jaGlsZHJlbi1wbGFjZWhvbGRlciB7XG4gIGRpc3BsYXk6IG5vbmU7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIG1hcmdpbjogMTFweDtcbiAgbWluLWhlaWdodDogODBweDtcbiAgYm9yZGVyOiAxcHggZGFzaGVkIHJnYmEoMTI0LCAxMjQsIDEyNCwgMC40KTtcbiAgYm9yZGVyLXJhZGl1czogNHB4O1xuICBwYWRkaW5nOiAxMnB4O1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgZm9udC1zaXplOiAxM3B4O1xuICBmb250LXN0eWxlOiBpdGFsaWM7XG4gIG9wYWNpdHk6IDAuNjtcbiAgdGV4dC1hbGlnbjogY2VudGVyO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250YWluZXIgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY2hpbGRyZW4ge1xuICBwYWRkaW5nOiAxMnB4O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250YWluZXIgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY2hpbGRyZW4gPiAubGF5b3V0LWVsZW1lbnQ6bm90KC5sYXlvdXQtY29udGFpbmVyKSArIC5sYXlvdXQtZWxlbWVudDpub3QoLmxheW91dC1jb250YWluZXIpIHtcbiAgbWFyZ2luLXRvcDogMTJweDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGFpbmVyID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNoaWxkcmVuID4gLnVpLXNvcnRhYmxlLWhlbHBlcjpmaXJzdC1jaGlsZCArIC5sYXlvdXQtZWxlbWVudDpub3QoLmxheW91dC1jb250YWluZXIpIHtcbiAgbWFyZ2luLXRvcDogMDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGFpbmVyID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIubGF5b3V0LWNvbnRhaW5lci1lbXB0eSA+IC5sYXlvdXQtY29udGFpbmVyLWNoaWxkcmVuLXBsYWNlaG9sZGVyIHtcbiAgZGlzcGxheTogZmxleDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGFpbmVyID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIubGF5b3V0LWNvbnRhaW5lci1lbXB0eSA+IC5sYXlvdXQtY2hpbGRyZW4ge1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMDtcbiAgcmlnaHQ6IDA7XG4gIGJvdHRvbTogMDtcbiAgbGVmdDogMDtcbn1cbi5sYXlvdXQtZWRpdG9yOm5vdCgubGF5b3V0LWVkaXRvci1kcmFnZ2luZykgLmxheW91dC1jb250YWluZXIubGF5b3V0LWVsZW1lbnQtZm9jdXNlZCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1jaGlsZHJlbiA+IC5sYXlvdXQtZWxlbWVudDpub3QoLmxheW91dC1lbGVtZW50LWFjdGl2ZSkge1xuICBib3JkZXI6IDFweCBkYXNoZWQgcmdiYSgxMjQsIDEyNCwgMTI0LCAwLjYpO1xufVxuLmxheW91dC1lZGl0b3I6bm90KC5sYXlvdXQtZWRpdG9yLWRyYWdnaW5nKSAubGF5b3V0LWNvbnRhaW5lci5sYXlvdXQtZWxlbWVudC1mb2N1c2VkID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNoaWxkcmVuID4gLmxheW91dC1lbGVtZW50Om5vdCgubGF5b3V0LWVsZW1lbnQtYWN0aXZlKSA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIHtcbiAgbWFyZ2luOiAtMXB4O1xufVxuLmxheW91dC1lZGl0b3I6bm90KC5sYXlvdXQtZWRpdG9yLWRyYWdnaW5nKSAubGF5b3V0LWNvbnRhaW5lci5sYXlvdXQtZWxlbWVudC1mb2N1c2VkID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNoaWxkcmVuID4gLmxheW91dC1jb250YWluZXIgKyAubGF5b3V0LWNvbnRhaW5lcjpub3QoLmxheW91dC1lbGVtZW50LWFjdGl2ZSkge1xuICBib3JkZXItdG9wOiAwO1xufVxuLmxheW91dC1lZGl0b3I6bm90KC5sYXlvdXQtZWRpdG9yLWRyYWdnaW5nKSAubGF5b3V0LWNvbnRhaW5lci5sYXlvdXQtZWxlbWVudC1mb2N1c2VkID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNoaWxkcmVuID4gLmxheW91dC1jb250YWluZXIgKyAubGF5b3V0LWNvbnRhaW5lcjpub3QoLmxheW91dC1lbGVtZW50LWFjdGl2ZSkgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciB7XG4gIG1hcmdpbi10b3A6IDA7XG59XG5cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY2FudmFzICNkdW1teSB7XG4gIGRpc3BsYXk6IG5vbmU7XG59XG5cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtcm93LmxheW91dC1lbGVtZW50LWZvY3VzZWQ6bm90KC5sYXlvdXQtZWxlbWVudC1kcm9wdGFyZ2V0KSA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1jaGlsZHJlbiA+IC5sYXlvdXQtZWxlbWVudDpub3QoLmxheW91dC1lbGVtZW50LWFjdGl2ZSkge1xuICBib3JkZXItdG9wOiAxcHggZGFzaGVkIHJnYmEoMTI0LCAxMjQsIDEyNCwgMC42KSAhaW1wb3J0YW50O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1yb3cubGF5b3V0LWVsZW1lbnQtZm9jdXNlZDpub3QoLmxheW91dC1lbGVtZW50LWRyb3B0YXJnZXQpID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNoaWxkcmVuID4gLmxheW91dC1lbGVtZW50Om5vdCgubGF5b3V0LWVsZW1lbnQtYWN0aXZlKSA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIHtcbiAgbWFyZ2luLXRvcDogLTFweCAhaW1wb3J0YW50O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1yb3cubGF5b3V0LWVsZW1lbnQtZm9jdXNlZDpub3QoLmxheW91dC1lbGVtZW50LWRyb3B0YXJnZXQpID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNoaWxkcmVuID4gLmxheW91dC1lbGVtZW50ICsgLmxheW91dC1lbGVtZW50Om5vdCgubGF5b3V0LWVsZW1lbnQtYWN0aXZlKSB7XG4gIGJvcmRlci1sZWZ0OiAwICFpbXBvcnRhbnQ7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LXJvdy5sYXlvdXQtZWxlbWVudC1mb2N1c2VkOm5vdCgubGF5b3V0LWVsZW1lbnQtZHJvcHRhcmdldCkgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY2hpbGRyZW4gPiAubGF5b3V0LWVsZW1lbnQgKyAubGF5b3V0LWVsZW1lbnQ6bm90KC5sYXlvdXQtZWxlbWVudC1hY3RpdmUpID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIge1xuICBtYXJnaW4tbGVmdDogMCAhaW1wb3J0YW50O1xufVxuXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbHVtbiA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1jb2x1bW4tcmVzaXplLWJhciB7XG4gIGRpc3BsYXk6IG5vbmU7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgei1pbmRleDogMzA7XG4gIHRvcDogMDtcbiAgd2lkdGg6IDE2cHg7XG4gIGhlaWdodDogMTAwJTtcbiAgY3Vyc29yOiBjb2wtcmVzaXplO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb2x1bW4gPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY29sdW1uLXJlc2l6ZS1iYXItbGVmdCB7XG4gIGxlZnQ6IC02cHg7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbHVtbiA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1jb2x1bW4tcmVzaXplLWJhci1yaWdodCB7XG4gIHJpZ2h0OiAtNnB4O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb2x1bW4ubGF5b3V0LWVsZW1lbnQtZm9jdXNlZCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1jb2x1bW4tcmVzaXplLWJhciB7XG4gIGRpc3BsYXk6IGJsb2NrO1xufVxuXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwge1xuICBtaW4taGVpZ2h0OiAxZW07XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB7XG4gIHBhZGRpbmc6IDJweDtcbiAgb3ZlcmZsb3cteDogaGlkZGVuO1xuICBsaW5lLWhlaWdodDogbm9ybWFsO1xuICAvKiB0aGlzIGNvbG9yIGlzIGp1c3QgYSBzdWdnZXN0aW9uIGFuZCBjYW4gYmUgY2hhbmdlZCBiYXNlZCBvbiBpbXBsZW1lbnRhdGlvbiBmZWVkYmFjayAqL1xuICAvKiB0aGlzIGFsc28gaGFzIGJpZGkgaW1wbGljYXRpb25zICovXG4gIC8qIHRoaXMgYWxzbyBoYXMgYmlkaSBpbXBsaWNhdGlvbnMgKi9cbiAgLyogTFRSLXNwZWNpZmljOiB1c2UgJ21hcmdpbi1yaWdodCcgZm9yIHJ0bCBlbGVtZW50cyAqL1xuICAvKiBMVFItc3BlY2lmaWM6IHVzZSAncGFkZGluZy1yaWdodCcgZm9yIHJ0bCBlbGVtZW50cyAqL1xuICAvKnRhYmxlW3J1bGVzPW5vbmUgaV0sIHRhYmxlW3J1bGVzPWdyb3VwcyBpXSwgdGFibGVbcnVsZXM9cm93cyBpXSxcbnRhYmxlW3J1bGVzPWNvbHMgaV0sIHRhYmxlW3J1bGVzPWFsbCBpXSwgdGFibGVbZnJhbWU9dm9pZCBpXSxcbnRhYmxlW2ZyYW1lPWFib3ZlIGldLCB0YWJsZVtmcmFtZT1iZWxvdyBpXSwgdGFibGVbZnJhbWU9aHNpZGVzIGldLFxudGFibGVbZnJhbWU9bGhzIGldLCB0YWJsZVtmcmFtZT1yaHMgaV0sIHRhYmxlW2ZyYW1lPXZzaWRlcyBpXSxcbnRhYmxlW2ZyYW1lPWJveCBpXSwgdGFibGVbZnJhbWU9Ym9yZGVyIGldLFxudGFibGVbcnVsZXM9bm9uZSBpXSA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPW5vbmUgaV0gPiB0ciA+IHRoLFxudGFibGVbcnVsZXM9Z3JvdXBzIGldID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9Z3JvdXBzIGldID4gdHIgPiB0aCxcbnRhYmxlW3J1bGVzPXJvd3MgaV0gPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1yb3dzIGldID4gdHIgPiB0aCxcbnRhYmxlW3J1bGVzPWNvbHMgaV0gPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1jb2xzIGldID4gdHIgPiB0aCxcbnRhYmxlW3J1bGVzPWFsbCBpXSA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWFsbCBpXSA+IHRyID4gdGgsXG50YWJsZVtydWxlcz1ub25lIGldID4gdGhlYWQgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1ub25lIGldID4gdGhlYWQgPiB0ciA+IHRoLFxudGFibGVbcnVsZXM9Z3JvdXBzIGldID4gdGhlYWQgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1ncm91cHMgaV0gPiB0aGVhZCA+IHRyID4gdGgsXG50YWJsZVtydWxlcz1yb3dzIGldID4gdGhlYWQgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1yb3dzIGldID4gdGhlYWQgPiB0ciA+IHRoLFxudGFibGVbcnVsZXM9Y29scyBpXSA+IHRoZWFkID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9Y29scyBpXSA+IHRoZWFkID4gdHIgPiB0aCxcbnRhYmxlW3J1bGVzPWFsbCBpXSA+IHRoZWFkID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9YWxsIGldID4gdGhlYWQgPiB0ciA+IHRoLFxudGFibGVbcnVsZXM9bm9uZSBpXSA+IHRib2R5ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9bm9uZSBpXSA+IHRib2R5ID4gdHIgPiB0aCxcbnRhYmxlW3J1bGVzPWdyb3VwcyBpXSA+IHRib2R5ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9Z3JvdXBzIGldID4gdGJvZHkgPiB0ciA+IHRoLFxudGFibGVbcnVsZXM9cm93cyBpXSA+IHRib2R5ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9cm93cyBpXSA+IHRib2R5ID4gdHIgPiB0aCxcbnRhYmxlW3J1bGVzPWNvbHMgaV0gPiB0Ym9keSA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWNvbHMgaV0gPiB0Ym9keSA+IHRyID4gdGgsXG50YWJsZVtydWxlcz1hbGwgaV0gPiB0Ym9keSA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWFsbCBpXSA+IHRib2R5ID4gdHIgPiB0aCxcbnRhYmxlW3J1bGVzPW5vbmUgaV0gPiB0Zm9vdCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPW5vbmUgaV0gPiB0Zm9vdCA+IHRyID4gdGgsXG50YWJsZVtydWxlcz1ncm91cHMgaV0gPiB0Zm9vdCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWdyb3VwcyBpXSA+IHRmb290ID4gdHIgPiB0aCxcbnRhYmxlW3J1bGVzPXJvd3MgaV0gPiB0Zm9vdCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPXJvd3MgaV0gPiB0Zm9vdCA+IHRyID4gdGgsXG50YWJsZVtydWxlcz1jb2xzIGldID4gdGZvb3QgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1jb2xzIGldID4gdGZvb3QgPiB0ciA+IHRoLFxudGFibGVbcnVsZXM9YWxsIGldID4gdGZvb3QgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1hbGwgaV0gPiB0Zm9vdCA+IHRyID4gdGgge1xuICAgIGJvcmRlci1jb2xvcjogYmxhY2s7XG59Ki9cbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgKixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgKiB7XG4gIG1hcmdpbjogMDtcbiAgcGFkZGluZzogMDtcbiAgYm94LXNpemluZzogY29udGVudC1ib3g7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGFkZHJlc3MsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGFkZHJlc3MsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJsb2NrcXVvdGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJsb2NrcXVvdGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNlbnRlcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgY2VudGVyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXYsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpdixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZmlndXJlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBmaWd1cmUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGZpZ2NhcHRpb24sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGZpZ2NhcHRpb24sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGZvb3Rlcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZm9vdGVyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBmb3JtLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBmb3JtLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoZWFkZXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGhlYWRlcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaHIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGhyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBsZWdlbmQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGxlZ2VuZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbGlzdGluZyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbGlzdGluZyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcGxhaW50ZXh0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBwbGFpbnRleHQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHByZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcHJlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB4bXAsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHhtcCB7XG4gIGRpc3BsYXk6IGJsb2NrO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBibG9ja3F1b3RlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBibG9ja3F1b3RlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBmaWd1cmUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGZpZ3VyZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbGlzdGluZyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbGlzdGluZyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcGxhaW50ZXh0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBwbGFpbnRleHQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHByZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcHJlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB4bXAsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHhtcCB7XG4gIG1hcmdpbi10b3A6IDFlbTtcbiAgbWFyZ2luLWJvdHRvbTogMWVtO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBibG9ja3F1b3RlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBibG9ja3F1b3RlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBmaWd1cmUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGZpZ3VyZSB7XG4gIG1hcmdpbi1sZWZ0OiA0MHB4O1xuICBtYXJnaW4tcmlnaHQ6IDQwcHg7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGFkZHJlc3MsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGFkZHJlc3Mge1xuICBmb250LXN0eWxlOiBpdGFsaWM7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGxpc3RpbmcsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGxpc3RpbmcsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHBsYWludGV4dCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcGxhaW50ZXh0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBwcmUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHByZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgeG1wLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB4bXAge1xuICBmb250LWZhbWlseTogbW9ub3NwYWNlO1xuICB3aGl0ZS1zcGFjZTogcHJlO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBjaXRlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBjaXRlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkZm4sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRmbixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZW0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGVtLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBpLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBpLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB2YXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHZhciB7XG4gIGZvbnQtc3R5bGU6IGl0YWxpYztcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc3Ryb25nLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzdHJvbmcge1xuICBmb250LXdlaWdodDogYm9sZGVyO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBjb2RlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBjb2RlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBrYmQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGtiZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc2FtcCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc2FtcCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdHQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHR0IHtcbiAgZm9udC1mYW1pbHk6IG1vbm9zcGFjZTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYmlnLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBiaWcge1xuICBmb250LXNpemU6IGxhcmdlcjtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc21hbGwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHNtYWxsIHtcbiAgZm9udC1zaXplOiBzbWFsbGVyO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzdWIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHN1YiB7XG4gIHZlcnRpY2FsLWFsaWduOiBzdWI7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHN1cCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc3VwIHtcbiAgdmVydGljYWwtYWxpZ246IHN1cGVyO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzdWIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHN1Yixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc3VwLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzdXAge1xuICBsaW5lLWhlaWdodDogbm9ybWFsO1xuICBmb250LXNpemU6IHNtYWxsZXI7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHJ1YnksXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHJ1Ynkge1xuICBkaXNwbGF5OiBydWJ5O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCByYixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcmIge1xuICBkaXNwbGF5OiBydWJ5LWJhc2U7XG4gIHdoaXRlLXNwYWNlOiBub3dyYXA7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHJ0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBydCB7XG4gIGRpc3BsYXk6IHJ1YnktdGV4dDtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgZm9udC1zaXplOiA1MCU7XG4gIGZvbnQtdmFyaWFudC1lYXN0LWFzaWFuOiBydWJ5O1xuICB0ZXh0LWVtcGhhc2lzOiBub25lO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCByYmMsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHJiYyB7XG4gIGRpc3BsYXk6IHJ1YnktYmFzZS1jb250YWluZXI7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHJ0Yyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcnRjIHtcbiAgZGlzcGxheTogcnVieS10ZXh0LWNvbnRhaW5lcjtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcnVieSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcnVieSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcmIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHJiLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBydCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcnQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHJiYyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcmJjLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBydGMsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHJ0YyB7XG4gIHVuaWNvZGUtYmlkaTogaXNvbGF0ZTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgOmxpbmssXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIDpsaW5rIHtcbiAgY29sb3I6ICMwMDAwRUU7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIDp2aXNpdGVkLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCA6dmlzaXRlZCB7XG4gIGNvbG9yOiAjNTUxQThCO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCA6bGluayxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgOmxpbmssXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIDp2aXNpdGVkLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCA6dmlzaXRlZCB7XG4gIHRleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBhOmxpbmtbcmVsfj1oZWxwXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYTpsaW5rW3JlbH49aGVscF0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGE6dmlzaXRlZFtyZWx+PWhlbHBdLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBhOnZpc2l0ZWRbcmVsfj1oZWxwXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYXJlYTpsaW5rW3JlbH49aGVscF0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGFyZWE6bGlua1tyZWx+PWhlbHBdLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBhcmVhOnZpc2l0ZWRbcmVsfj1oZWxwXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYXJlYTp2aXNpdGVkW3JlbH49aGVscF0ge1xuICBjdXJzb3I6IGhlbHA7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIDpmb2N1cyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgOmZvY3VzIHtcbiAgb3V0bGluZTogYXV0bztcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbWFyayxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbWFyayB7XG4gIGJhY2tncm91bmQ6IHllbGxvdztcbiAgY29sb3I6IGJsYWNrO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBhYmJyW3RpdGxlXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYWJiclt0aXRsZV0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGFjcm9ueW1bdGl0bGVdLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBhY3JvbnltW3RpdGxlXSB7XG4gIHRleHQtZGVjb3JhdGlvbjogZG90dGVkIHVuZGVybGluZTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaW5zLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBpbnMsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHUge1xuICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkZWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHMsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHMsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHN0cmlrZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc3RyaWtlIHtcbiAgdGV4dC1kZWNvcmF0aW9uOiBsaW5lLXRocm91Z2g7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJsaW5rLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBibGluayB7XG4gIHRleHQtZGVjb3JhdGlvbjogYmxpbms7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHE6OmJlZm9yZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcTo6YmVmb3JlIHtcbiAgY29udGVudDogb3Blbi1xdW90ZTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgcTo6YWZ0ZXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHE6OmFmdGVyIHtcbiAgY29udGVudDogY2xvc2UtcXVvdGU7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJyOjpiZWZvcmUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJyOjpiZWZvcmUge1xuICBjb250ZW50OiAnXFxBJztcbiAgd2hpdGUtc3BhY2U6IHByZTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbm9icixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbm9iciB7XG4gIHdoaXRlLXNwYWNlOiBub3dyYXA7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHdicixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgd2JyIHtcbiAgY29udGVudDogJ1xcMjAwQic7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG5vYnIgd2JyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBub2JyIHdiciB7XG4gIHdoaXRlLXNwYWNlOiBub3JtYWw7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGFydGljbGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGFydGljbGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGFzaWRlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBhc2lkZSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaDEsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGgxLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoMixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaDIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGgzLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoMyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaDQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGg0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoNSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaDUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGg2LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoNixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaGdyb3VwLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoZ3JvdXAsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG5hdixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbmF2LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzZWN0aW9uLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBzZWN0aW9uIHtcbiAgZGlzcGxheTogYmxvY2s7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGgxLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoMSB7XG4gIG1hcmdpbi10b3A6IDAuNjdlbTtcbiAgbWFyZ2luLWJvdHRvbTogMC42N2VtO1xuICBmb250LXNpemU6IDIuMDBlbTtcbiAgZm9udC13ZWlnaHQ6IGJvbGQ7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGgyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoMiB7XG4gIG1hcmdpbi10b3A6IDAuODNlbTtcbiAgbWFyZ2luLWJvdHRvbTogMC44M2VtO1xuICBmb250LXNpemU6IDEuNTBlbTtcbiAgZm9udC13ZWlnaHQ6IGJvbGQ7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGgzLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoMyB7XG4gIG1hcmdpbi10b3A6IDEuMDBlbTtcbiAgbWFyZ2luLWJvdHRvbTogMS4wMGVtO1xuICBmb250LXNpemU6IDEuMTdlbTtcbiAgZm9udC13ZWlnaHQ6IGJvbGQ7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGg0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoNCB7XG4gIG1hcmdpbi10b3A6IDEuMzNlbTtcbiAgbWFyZ2luLWJvdHRvbTogMS4zM2VtO1xuICBmb250LXNpemU6IDEuMDBlbTtcbiAgZm9udC13ZWlnaHQ6IGJvbGQ7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGg1LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoNSB7XG4gIG1hcmdpbi10b3A6IDEuNjdlbTtcbiAgbWFyZ2luLWJvdHRvbTogMS42N2VtO1xuICBmb250LXNpemU6IDAuODNlbTtcbiAgZm9udC13ZWlnaHQ6IGJvbGQ7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGg2LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBoNiB7XG4gIG1hcmdpbi10b3A6IDIuMzNlbTtcbiAgbWFyZ2luLWJvdHRvbTogMi4zM2VtO1xuICBmb250LXNpemU6IDAuNjdlbTtcbiAgZm9udC13ZWlnaHQ6IGJvbGQ7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZHQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGR0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCB7XG4gIGRpc3BsYXk6IGJsb2NrO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBsaSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbGkge1xuICBkaXNwbGF5OiBsaXN0LWl0ZW07XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIHtcbiAgbWFyZ2luLXRvcDogMWVtO1xuICBtYXJnaW4tYm90dG9tOiAxZW07XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciBkbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIGRsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIgb2wsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciBvbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRsIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGwgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkbCBkbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGwgZGwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRsIG9sLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkbCBvbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGwgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRsIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wgZGwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIGRsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCBvbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wgb2wsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIGRsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCBkbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgb2wsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIG9sLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgdWwge1xuICBtYXJnaW4tdG9wOiAwO1xuICBtYXJnaW4tYm90dG9tOiAwO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGQge1xuICBtYXJnaW4tbGVmdDogNDBweDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIHtcbiAgcGFkZGluZy1sZWZ0OiA0MHB4O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wge1xuICBsaXN0LXN0eWxlLXR5cGU6IGRlY2ltYWw7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwge1xuICBsaXN0LXN0eWxlLXR5cGU6IGRpc2M7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIHVsIHtcbiAgbGlzdC1zdHlsZS10eXBlOiBjaXJjbGU7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciBkaXIgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIgZGlyIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIGRpciB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIGRpciB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIG9sIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIG9sIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIG9sIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBkaXIgb2wgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciB1bCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciB1bCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGRpciB1bCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZGlyIHVsIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCBkaXIgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCBkaXIgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCBkaXIgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIGRpciB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wgb2wgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCBvbCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIG9sIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCBvbCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb2wgdWwgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCB1bCBkaXIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9sIHVsIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvbCB1bCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgZGlyIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgZGlyIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgZGlyIHVsLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCBkaXIgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIG9sIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgb2wgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCBvbCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgb2wgdWwsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHVsIHVsIGRpcixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgdWwgZGlyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB1bCB1bCB1bCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdWwgdWwgdWwge1xuICBsaXN0LXN0eWxlLXR5cGU6IHNxdWFyZTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGFibGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRhYmxlIHtcbiAgZGlzcGxheTogdGFibGU7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNhcHRpb24sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNhcHRpb24ge1xuICBkaXNwbGF5OiB0YWJsZS1jYXB0aW9uO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBjb2xncm91cCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgY29sZ3JvdXAsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNvbGdyb3VwW2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNvbGdyb3VwW2hpZGRlbl0ge1xuICBkaXNwbGF5OiB0YWJsZS1jb2x1bW4tZ3JvdXA7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGNvbCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgY29sLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBjb2xbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgY29sW2hpZGRlbl0ge1xuICBkaXNwbGF5OiB0YWJsZS1jb2x1bW47XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoZWFkLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0aGVhZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGhlYWRbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGhlYWRbaGlkZGVuXSB7XG4gIGRpc3BsYXk6IHRhYmxlLWhlYWRlci1ncm91cDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGJvZHksXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRib2R5LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0Ym9keVtoaWRkZW5dLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0Ym9keVtoaWRkZW5dIHtcbiAgZGlzcGxheTogdGFibGUtcm93LWdyb3VwO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0Zm9vdCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGZvb3QsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRmb290W2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRmb290W2hpZGRlbl0ge1xuICBkaXNwbGF5OiB0YWJsZS1mb290ZXItZ3JvdXA7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0cixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdHJbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdHJbaGlkZGVuXSB7XG4gIGRpc3BsYXk6IHRhYmxlLXJvdztcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRkLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0aCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGgsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRkW2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRkW2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoW2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoW2hpZGRlbl0ge1xuICBkaXNwbGF5OiB0YWJsZS1jZWxsO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBjb2xncm91cFtoaWRkZW5dLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBjb2xncm91cFtoaWRkZW5dLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBjb2xbaGlkZGVuXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgY29sW2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoZWFkW2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoZWFkW2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRib2R5W2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRib2R5W2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRmb290W2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRmb290W2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRyW2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRyW2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRkW2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRkW2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoW2hpZGRlbl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoW2hpZGRlbl0ge1xuICB2aXNpYmlsaXR5OiBjb2xsYXBzZTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGFibGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRhYmxlIHtcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgYm9yZGVyLXNwYWNpbmc6IDJweDtcbiAgYm9yZGVyLWNvbGxhcHNlOiBzZXBhcmF0ZTtcbiAgdGV4dC1pbmRlbnQ6IGluaXRpYWw7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRkLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0ZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGgsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoIHtcbiAgcGFkZGluZzogMXB4O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0aCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGgge1xuICBmb250LXdlaWdodDogYm9sZDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGhlYWQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoZWFkLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0Ym9keSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGJvZHksXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRmb290LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0Zm9vdCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGFibGUgPiB0cixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGFibGUgPiB0ciB7XG4gIHZlcnRpY2FsLWFsaWduOiBtaWRkbGU7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0cixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRkLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0aCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGgge1xuICB2ZXJ0aWNhbC1hbGlnbjogaW5oZXJpdDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGFibGUsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRhYmxlLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0ZCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0aCB7XG4gIGJvcmRlci1jb2xvcjogZ3JheTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGhlYWQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRoZWFkLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0Ym9keSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGJvZHksXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRmb290LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0Zm9vdCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdHIsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRyIHtcbiAgYm9yZGVyLWNvbG9yOiBpbmhlcml0O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBpbnB1dCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaW5wdXQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHNlbGVjdCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc2VsZWN0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBvcHRpb24sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9wdGlvbixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgb3B0Z3JvdXAsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIG9wdGdyb3VwLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBidXR0b24sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJ1dHRvbixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGV4dGFyZWEsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHRleHRhcmVhLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBrZXlnZW4sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGtleWdlbiB7XG4gIHRleHQtaW5kZW50OiBpbml0aWFsO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCB0ZXh0YXJlYSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgdGV4dGFyZWEge1xuICB3aGl0ZS1zcGFjZTogcHJlLXdyYXA7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGlucHV0W3R5cGU9XCJyYWRpb1wiXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaW5wdXRbdHlwZT1cInJhZGlvXCJdLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBpbnB1dFt0eXBlPVwiY2hlY2tib3hcIl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGlucHV0W3R5cGU9XCJjaGVja2JveFwiXSxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgaW5wdXRbdHlwZT1cInJlc2V0XCJdLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBpbnB1dFt0eXBlPVwicmVzZXRcIl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGlucHV0W3R5cGU9XCJidXR0b25cIl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGlucHV0W3R5cGU9XCJidXR0b25cIl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGlucHV0W3R5cGU9XCJzdWJtaXRcIl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGlucHV0W3R5cGU9XCJzdWJtaXRcIl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIHNlbGVjdCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgc2VsZWN0LFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBidXR0b24sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJ1dHRvbiB7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGlucHV0W3R5cGU9XCJidXR0b25cIl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGlucHV0W3R5cGU9XCJidXR0b25cIl0sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGJ1dHRvbixcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgYnV0dG9uIHtcbiAgcGFkZGluZzogMC4zZW0gMC41ZW07XG59XG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWNvbnRlbnQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwIGhyLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBociB7XG4gIGNvbG9yOiBncmF5O1xuICBib3JkZXItc3R5bGU6IGluc2V0O1xuICBib3JkZXItd2lkdGg6IDFweDtcbiAgbWFyZ2luOiAwLjVlbSBhdXRvO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBmaWVsZHNldCxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgZmllbGRzZXQge1xuICBtYXJnaW4tbGVmdDogMnB4O1xuICBtYXJnaW4tcmlnaHQ6IDJweDtcbiAgYm9yZGVyOiBncm9vdmUgMnB4IFRocmVlREZhY2U7XG4gIHBhZGRpbmc6IDAuMzVlbSAwLjYyNWVtIDAuNzVlbTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgbGVnZW5kLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCBsZWdlbmQge1xuICBwYWRkaW5nLWxlZnQ6IDJweDtcbiAgcGFkZGluZy1yaWdodDogMnB4O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50ID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgLmxheW91dC1jb250ZW50LW1hcmt1cCA+ICo6Zmlyc3QtY2hpbGQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwID4gKjpmaXJzdC1jaGlsZCB7XG4gIG1hcmdpbi10b3A6IDAgIWltcG9ydGFudDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtY29udGVudCA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIC5sYXlvdXQtY29udGVudC1tYXJrdXAgPiAqOmxhc3QtY2hpbGQsXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LWh0bWwgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciAubGF5b3V0LWNvbnRlbnQtbWFya3VwID4gKjpsYXN0LWNoaWxkIHtcbiAgbWFyZ2luLWJvdHRvbTogMCAhaW1wb3J0YW50O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50LmxheW91dC1jb250ZW50LWltYWdlID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNvbnRlbnQtbWFya3VwID4gaW1nLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1odG1sLmxheW91dC1jb250ZW50LWltYWdlID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNvbnRlbnQtbWFya3VwID4gaW1nLFxuLmxheW91dC1lZGl0b3IgLmxheW91dC1jb250ZW50LmxheW91dC1jb250ZW50LXZlY3Rvci1pbWFnZSA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1jb250ZW50LW1hcmt1cCA+IGltZyxcbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtaHRtbC5sYXlvdXQtY29udGVudC12ZWN0b3ItaW1hZ2UgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY29udGVudC1tYXJrdXAgPiBpbWcge1xuICBkaXNwbGF5OiBibG9jaztcbiAgd2lkdGg6IDEwMCU7XG4gIG1heC13aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiBhdXRvO1xufVxuLmxheW91dC1lZGl0b3IgLmltZy1yZXNwb25zaXZlLFxuLmxheW91dC1lZGl0b3IgLmltZy1yZXNwb25zaXZlIGltZyB7XG4gIGRpc3BsYXk6IGJsb2NrO1xuICB3aWR0aDogMTAwJTtcbiAgbWF4LXdpZHRoOiAxMDAlO1xuICBoZWlnaHQ6IGF1dG87XG59XG5cbmJvZHkgLmxheW91dC10b29sYm94LWl0ZW0ge1xuICBib3JkZXI6IDFweCBzb2xpZCAjZTRlNWU2O1xuICBiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmO1xuICBwYWRkaW5nOiA5cHggMTJweDtcbiAgY3Vyc29yOiBkZWZhdWx0O1xuICBsaXN0LXN0eWxlLXR5cGU6IG5vbmU7XG59XG5ib2R5IC5sYXlvdXQtdG9vbGJveC1pdGVtIGkge1xuICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gIHdpZHRoOiAxNnB4O1xuICBmb250OiBub3JtYWwgbm9ybWFsIG5vcm1hbCAxNHB4LzEgRm9udEF3ZXNvbWU7XG59XG5ib2R5IC5sYXlvdXQtdG9vbGJveC1pdGVtICsgLmxheW91dC10b29sYm94LWl0ZW0ge1xuICBtYXJnaW4tdG9wOiA0cHg7XG59XG4ubGF5b3V0LWVkaXRvciA+IC5sYXlvdXQtdG9vbGJveC13cmFwcGVyIHtcbiAgcG9zaXRpb246IHN0aWNreTtcbiAgdG9wOiAxdmg7XG4gIHBhZGRpbmctbGVmdDogMTJweDtcbiAgd2lkdGg6IDIyMHB4O1xuICBvdmVyZmxvdy15OiBhdXRvO1xuICBzY3JvbGxiYXItd2lkdGg6IHRoaW47XG4gIG1pbi1oZWlnaHQ6IDQwMHB4O1xuICBtYXgtaGVpZ2h0OiA5OHZoO1xuICBoZWlnaHQ6IDEwMCU7XG59XG4ubGF5b3V0LWVkaXRvciA+IC5sYXlvdXQtdG9vbGJveC13cmFwcGVyID4gLmxheW91dC10b29sYm94IHtcbiAgYm9yZGVyOiAxcHggc29saWQgI2U0ZTVlNjtcbiAgcGFkZGluZzogNnB4O1xuICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjNmNGY1O1xufVxuLmxheW91dC1lZGl0b3IgPiAubGF5b3V0LXRvb2xib3gtd3JhcHBlciA+IC5sYXlvdXQtdG9vbGJveCAubGF5b3V0LXRvb2xib3gtZ3JvdXAgLmxheW91dC10b29sYm94LWdyb3VwLWhlYWRpbmcge1xuICBkaXNwbGF5OiBibG9jaztcbiAgbWFyZ2luLWJvdHRvbTogNHB4O1xuICB0ZXh0LWRlY29yYXRpb246IG5vbmU7XG59XG4ubGF5b3V0LWVkaXRvciA+IC5sYXlvdXQtdG9vbGJveC13cmFwcGVyID4gLmxheW91dC10b29sYm94IC5sYXlvdXQtdG9vbGJveC1ncm91cCAubGF5b3V0LXRvb2xib3gtZ3JvdXAtaGVhZGluZzpiZWZvcmUge1xuICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gIHdpZHRoOiAxMHB4O1xuICBtYXJnaW4tcmlnaHQ6IDRweDtcbiAgZm9udDogbm9ybWFsIG5vcm1hbCBub3JtYWwgMTRweC8xIEZvbnRBd2Vzb21lO1xuICB0ZXh0LWFsaWduOiBjZW50ZXI7XG4gIGNvbnRlbnQ6IFwiXFxmMGQ3XCI7XG59XG4ubGF5b3V0LWVkaXRvciA+IC5sYXlvdXQtdG9vbGJveC13cmFwcGVyID4gLmxheW91dC10b29sYm94IC5sYXlvdXQtdG9vbGJveC1ncm91cC5jb2xsYXBzZWQgLmxheW91dC10b29sYm94LWdyb3VwLWhlYWRpbmc6YmVmb3JlIHtcbiAgY29udGVudDogXCJcXGYwZGFcIjtcbn1cbi5sYXlvdXQtZWRpdG9yID4gLmxheW91dC10b29sYm94LXdyYXBwZXIgPiAubGF5b3V0LXRvb2xib3ggLmxheW91dC10b29sYm94LWdyb3VwLmNvbGxhcHNlZCAubGF5b3V0LXRvb2xib3gtaXRlbXMge1xuICBkaXNwbGF5OiBub25lO1xufVxuLmxheW91dC1lZGl0b3IgPiAubGF5b3V0LXRvb2xib3gtd3JhcHBlciA+IC5sYXlvdXQtdG9vbGJveCAubGF5b3V0LXRvb2xib3gtZ3JvdXAgLmxheW91dC10b29sYm94LXNlY3Rpb24gKyAubGF5b3V0LXRvb2xib3gtc2VjdGlvbiB7XG4gIG1hcmdpbi10b3A6IDRweDtcbn1cbi5sYXlvdXQtZWRpdG9yID4gLmxheW91dC10b29sYm94LXdyYXBwZXIgPiAubGF5b3V0LXRvb2xib3ggLmxheW91dC10b29sYm94LWdyb3VwIC5sYXlvdXQtdG9vbGJveC1pdGVtIHtcbiAgYm9yZGVyOiAxcHggc29saWQgI2U0ZTVlNjtcbiAgYmFja2dyb3VuZC1jb2xvcjogI2ZmZjtcbiAgcGFkZGluZzogOXB4IDEycHg7XG4gIGN1cnNvcjogZGVmYXVsdDtcbn1cbi5sYXlvdXQtZWRpdG9yID4gLmxheW91dC10b29sYm94LXdyYXBwZXIgPiAubGF5b3V0LXRvb2xib3ggLmxheW91dC10b29sYm94LWdyb3VwIC5sYXlvdXQtdG9vbGJveC1pdGVtIGkge1xuICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gIHdpZHRoOiAxNnB4O1xuICBmb250OiBub3JtYWwgbm9ybWFsIG5vcm1hbCAxNHB4LzEgRm9udEF3ZXNvbWU7XG59XG4ubGF5b3V0LWVkaXRvciA+IC5sYXlvdXQtdG9vbGJveC13cmFwcGVyID4gLmxheW91dC10b29sYm94IC5sYXlvdXQtdG9vbGJveC1ncm91cCAubGF5b3V0LXRvb2xib3gtaXRlbSArIC5sYXlvdXQtdG9vbGJveC1pdGVtIHtcbiAgbWFyZ2luLXRvcDogNHB4O1xufVxuLmxheW91dC1lZGl0b3IgPiAubGF5b3V0LXRvb2xib3gtd3JhcHBlciA+IC5sYXlvdXQtdG9vbGJveCAubGF5b3V0LXRvb2xib3gtZ3JvdXAgKyAubGF5b3V0LXRvb2xib3gtZ3JvdXAge1xuICBtYXJnaW4tdG9wOiA2cHg7XG59XG5cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtcG9wdXAge1xuICBkaXNwbGF5OiBub25lO1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIG1hcmdpbjogMDtcbiAgLW1vei1ib3gtc2hhZG93OiAzcHggM3B4IDExcHggMCByZ2JhKDUwLCA1MCwgNTAsIDAuNSk7XG4gIC13ZWJraXQtYm94LXNoYWRvdzogM3B4IDNweCAxMXB4IDAgcmdiYSg1MCwgNTAsIDUwLCAwLjUpO1xuICBib3gtc2hhZG93OiAzcHggM3B4IDExcHggMCByZ2JhKDUwLCA1MCwgNTAsIDAuNSk7XG4gIGJvcmRlcjogMXB4IHNvbGlkICNlNGU1ZTY7XG4gIHBhZGRpbmc6IDJweCAwO1xuICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjdmN2Y3O1xuICBsaXN0LXN0eWxlOiBub25lO1xuICB6LWluZGV4OiAyMDtcbiAgY29sb3I6ICM3YzdjN2M7XG4gIHRleHQtYWxpZ246IGxlZnQ7XG4gIGN1cnNvcjogZGVmYXVsdDtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgbGluZS1oZWlnaHQ6IG5vcm1hbDtcbiAgbWluLXdpZHRoOiAzMDBweDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtcG9wdXAud2lkZSB7XG4gIHdpZHRoOiA2MDBweDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtcG9wdXAgLmxheW91dC1wb3B1cC1mbGV4IHtcbiAgZGlzcGxheTogZmxleDtcbiAgcGFkZGluZzogMnB4IDVweDtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtcG9wdXAgLmxheW91dC1wb3B1cC1mbGV4IC5sYXlvdXQtcG9wdXAtY29sdW1uICsgLmxheW91dC1wb3B1cC1jb2x1bW4ge1xuICBtYXJnaW4tbGVmdDogNHB4O1xuICBib3JkZXItbGVmdDogMXB4IHNvbGlkIHJnYmEoMTI4LCAxMjgsIDEyOCwgMC4xNSk7XG4gIHBhZGRpbmctbGVmdDogNHB4O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1wb3B1cCAubGF5b3V0LXBvcHVwLWl0ZW0ge1xuICBwYWRkaW5nOiA0cHggNnB4O1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1wb3B1cCAubGF5b3V0LXBvcHVwLWxhYmVsIHtcbiAgZm9udC1zaXplOiAwLjllbTtcbiAgZm9udC13ZWlnaHQ6IGJvbGQ7XG4gIGNvbG9yOiAjN2M3YzdjO1xufVxuLmxheW91dC1lZGl0b3IgLmxheW91dC1wb3B1cCAubGF5b3V0LXBvcHVwLWFjdGlvbjpob3ZlciB7XG4gIGJhY2tncm91bmQtY29sb3I6ICNmM2Y0ZjU7XG4gIGN1cnNvcjogcG9pbnRlcjtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtcG9wdXAgLmxheW91dC1wb3B1cC1pbnB1dCBpbnB1dFt0eXBlPSd0ZXh0J10sXG4ubGF5b3V0LWVkaXRvciAubGF5b3V0LXBvcHVwIC5sYXlvdXQtcG9wdXAtaW5wdXQgdGV4dGFyZWEge1xuICB3aWR0aDogMTAwJTtcbn1cbi5sYXlvdXQtZWRpdG9yIC5sYXlvdXQtcG9wdXAgLmxheW91dC1wb3B1cC1pbnB1dCA+IGxhYmVsIHtcbiAgZGlzcGxheTogYmxvY2s7XG4gIGZvbnQtc2l6ZTogMC45ZW07XG59XG4iLCLvu79AaW1wb3J0IFwiVmFyaWFibGVzLmxlc3NcIjtcclxuXHJcbi5sYXlvdXQtZWRpdG9yIHtcclxuICAgIC5sYXlvdXQtZWxlbWVudCB7XHJcbiAgICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xyXG4gICAgICAgIG1hcmdpbi10b3A6IDA7XHJcbiAgICAgICAgbWFyZ2luLXJpZ2h0OiAwO1xyXG4gICAgICAgIG1hcmdpbi1ib3R0b206IDA7XHJcbiAgICAgICAgcGFkZGluZzogMDtcclxuXHJcbiAgICAgICAgLy8gV2UgZG9uJ3QgZnVjayB3aXRoIHRoZSBsZWZ0IG1hcmdpbiBvZiBjb2x1bW5zLCBiZWNhdXNlIEJvb3RzdHJhcCB1c2VzIHRoZXNlIHRvIHJlbmRlciBjb2x1bW4gb2Zmc2V0cy5cclxuICAgICAgICAmOm5vdCgubGF5b3V0LWNvbHVtbikge1xyXG4gICAgICAgICAgICBtYXJnaW4tbGVmdDogMDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIge1xyXG4gICAgICAgICAgICA+IC5sYXlvdXQtcGFuZWwge1xyXG4gICAgICAgICAgICAgICAgZGlzcGxheTogbm9uZTsgLy8gU2hvd24gb25seSBpbiBhY3RpdmUgb3IgZm9jdXNlZCBzdGF0ZXMuXHJcbiAgICAgICAgICAgICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgICAgICAgICAgICAgICBtYXJnaW46IDA7XHJcbiAgICAgICAgICAgICAgICB6LWluZGV4OiAyMDtcclxuICAgICAgICAgICAgICAgIGhlaWdodDogMjVweDtcclxuICAgICAgICAgICAgICAgIHBhZGRpbmc6IDAgNnB4O1xyXG4gICAgICAgICAgICAgICAgbGlzdC1zdHlsZTogbm9uZTtcclxuICAgICAgICAgICAgICAgIHdoaXRlLXNwYWNlOiBub3dyYXA7XHJcbiAgICAgICAgICAgICAgICBsaW5lLWhlaWdodDogMjVweDtcclxuICAgICAgICAgICAgICAgIHZlcnRpY2FsLWFsaWduOiBtaWRkbGU7XHJcblxyXG4gICAgICAgICAgICAgICAgPiAubGF5b3V0LXBhbmVsLWl0ZW0ge1xyXG4gICAgICAgICAgICAgICAgICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcclxuICAgICAgICAgICAgICAgICAgICBoZWlnaHQ6IDI1cHg7XHJcbiAgICAgICAgICAgICAgICAgICAgcGFkZGluZzogMXB4IDZweCAwO1xyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgID4gLmxheW91dC1wYW5lbC1sYWJlbCB7XHJcbiAgICAgICAgICAgICAgICAgICAgZm9udC1zaXplOiBAZm9udC1zaXplIC0gMTtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICA+IC5sYXlvdXQtcGFuZWwtYWN0aW9uIHtcclxuICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBub25lOyAvLyBTaG93biBvbmx5IGluIGZvY3VzZWQgc3RhdGUuXHJcbiAgICAgICAgICAgICAgICAgICAgd2lkdGg6IDI4cHg7XHJcbiAgICAgICAgICAgICAgICAgICAgY3Vyc29yOiBwb2ludGVyO1xyXG4gICAgICAgICAgICAgICAgICAgIHRleHQtYWxpZ246IGNlbnRlcjtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgPiAubGF5b3V0LXBhbmVsLW1haW4ge1xyXG4gICAgICAgICAgICAgICAgdG9wOiAtMjdweDtcclxuICAgICAgICAgICAgICAgIGxlZnQ6IC0ycHg7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2hlbiBkcmFnZ2luZyBmcm9tIHRvb2xib3gsIGVsZW1lbnRzIHdpbGwgYmUgbGkgcmF0aGVyIHRoYW4gZGl2LlxyXG4gICAgbGkubGF5b3V0LWVsZW1lbnQge1xyXG4gICAgICAgIGxpc3Qtc3R5bGU6IG5vbmU7XHJcbiAgICB9XHJcblxyXG4gICAgJjpub3QoLmxheW91dC1lZGl0b3ItZHJhZ2dpbmcpIHtcclxuXHJcbiAgICAgICAgLmxheW91dC1lbGVtZW50LWFjdGl2ZSwgLmxheW91dC1lbGVtZW50LWZvY3VzZWQge1xyXG4gICAgICAgICAgICBib3JkZXItd2lkdGg6IDJweDtcclxuICAgICAgICAgICAgYm9yZGVyLXN0eWxlOiBzb2xpZDtcclxuXHJcbiAgICAgICAgICAgID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIge1xyXG4gICAgICAgICAgICAgICAgbWFyZ2luOiAtMnB4O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAubGF5b3V0LWVsZW1lbnQtYWN0aXZlIHtcclxuICAgICAgICAgICAgQGFjdGl2ZS1oaWdobGlnaHQ6IGZhZGUoIzY4Njg2OCwgMTAlKTtcclxuXHJcbiAgICAgICAgICAgIGJvcmRlci1jb2xvcjogQGFjdGl2ZS1oaWdobGlnaHQ7XHJcblxyXG4gICAgICAgICAgICA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyID4gLmxheW91dC1wYW5lbC1tYWluIHtcclxuICAgICAgICAgICAgICAgIGRpc3BsYXk6IGJsb2NrOyAvLyBUbyByZXZlYWwuXHJcbiAgICAgICAgICAgICAgICB6LWluZGV4OiAzMDtcclxuICAgICAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IEBhY3RpdmUtaGlnaGxpZ2h0O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAubGF5b3V0LWVsZW1lbnQtZm9jdXNlZCB7XHJcbiAgICAgICAgICAgIEBmb2N1c2VkLWhpZ2hsaWdodDogIzY0ODcyMTtcclxuICAgICAgICAgICAgQGZvY3VzZWQtdGV4dDogI2ZlZmVmZTtcclxuXHJcbiAgICAgICAgICAgIGJvcmRlci1jb2xvcjogQGZvY3VzZWQtaGlnaGxpZ2h0O1xyXG5cclxuICAgICAgICAgICAgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtcGFuZWwge1xyXG4gICAgICAgICAgICAgICAgZGlzcGxheTogYmxvY2s7IC8vIFRvIHJldmVhbC5cclxuICAgICAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IEBmb2N1c2VkLWhpZ2hsaWdodDtcclxuICAgICAgICAgICAgICAgIGNvbG9yOiBAZm9jdXNlZC10ZXh0O1xyXG5cclxuICAgICAgICAgICAgICAgID4gLmxheW91dC1wYW5lbC1hY3Rpb24ge1xyXG4gICAgICAgICAgICAgICAgICAgIGRpc3BsYXk6IGlubGluZS1ibG9jazsgLy8gVG8gcmV2ZWFsLlxyXG4gICAgICAgICAgICAgICAgICAgICY6aG92ZXIge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGVuKEBmb2N1c2VkLWhpZ2hsaWdodCwgMTAlKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICYuZGlzYWJsZWQge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjdXJzb3I6IGRlZmF1bHQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yOiBmYWRlKEBmb2N1c2VkLXRleHQsIDQwJSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAmOmhvdmVyIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IEBmb2N1c2VkLWhpZ2hsaWdodDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgJi5hY3RpdmUge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb2xvcjogbGlnaHRlbihzYXR1cmF0ZShzcGluKEBmb2N1c2VkLWhpZ2hsaWdodCwgLTEwKSwgMTAwJSksIDMwJSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IGxpZ2h0ZW4oQGZvY3VzZWQtaGlnaGxpZ2h0LCA1JSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAmOmhvdmVyIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IGxpZ2h0ZW4oQGZvY3VzZWQtaGlnaGxpZ2h0LCAxMCUpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAubGF5b3V0LWVsZW1lbnQtc2VsZWN0ZWQge1xyXG4gICAgICAgICAgICBAc2VsZWN0ZWQtaGlnaGxpZ2h0OiAjNjQ4NzIxO1xyXG4gICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiBmYWRlKEBzZWxlY3RlZC1oaWdobGlnaHQsIDglKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLnVpLXNvcnRhYmxlLXBsYWNlaG9sZGVyIHtcclxuICAgICAgICBkaXNwbGF5OiBub25lO1xyXG4gICAgfVxyXG5cclxuICAgIC5sYXlvdXQtZWxlbWVudC1kcm9wdGFyZ2V0IHtcclxuICAgICAgICBAZHJvcHRhcmdldC1oaWdobGlnaHQ6ICM2NDg3MjE7XHJcbiAgICAgICAgYm94LXNoYWRvdzogaW5zZXQgMCAwIDEycHggNnB4IGZhZGUoQGRyb3B0YXJnZXQtaGlnaGxpZ2h0LCA1MCUpO1xyXG5cclxuICAgICAgICAudWktc29ydGFibGUtcGxhY2Vob2xkZXIge1xyXG4gICAgICAgICAgICBkaXNwbGF5OiBibG9jazsgLy8gVG8gcmV2ZWFsLlxyXG4gICAgICAgICAgICB2aXNpYmlsaXR5OiB2aXNpYmxlICFpbXBvcnRhbnQ7XHJcbiAgICAgICAgICAgIG1pbi1oZWlnaHQ6IEBlbGVtZW50LW1pbi1oZWlnaHQgLSAycHg7XHJcbiAgICAgICAgICAgIGJvcmRlcjogMnB4IGRhc2hlZCBAZHJvcHRhcmdldC1oaWdobGlnaHQgIWltcG9ydGFudDtcclxuICAgICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogZmFkZShAZHJvcHRhcmdldC1oaWdobGlnaHQsIDE2JSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEEgQ1NTIGZpeCBmb3IgbWVkaWEgaXRlbSBlbGVtZW50cy5cclxuICAgIC5tZWRpYS10aHVtYm5haWwge1xyXG4gICAgICAgIGltZyB7XHJcbiAgICAgICAgICAgIG1heC13aWR0aDoxMDAlO1xyXG4gICAgICAgICAgICBtYXgtaGVpZ2h0OiAxMDAlO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG4iLCLvu79AaW1wb3J0IFwiVmFyaWFibGVzLmxlc3NcIjtcclxuXHJcbi5sYXlvdXQtZWRpdG9yIHtcclxuICAgIC5sYXlvdXQtY29udGFpbmVyIHtcclxuXHJcbiAgICAgICAgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciB7XHJcblxyXG4gICAgICAgICAgICA+IC5sYXlvdXQtY29udGFpbmVyLWNoaWxkcmVuLXBsYWNlaG9sZGVyIHtcclxuICAgICAgICAgICAgICAgIGRpc3BsYXk6IG5vbmU7XHJcbiAgICAgICAgICAgICAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xyXG4gICAgICAgICAgICAgICAgbWFyZ2luOiBAY29udGFpbmVyLXBhZGRpbmcgLSAxcHg7XHJcbiAgICAgICAgICAgICAgICBtaW4taGVpZ2h0OiBAZWxlbWVudC1taW4taGVpZ2h0O1xyXG4gICAgICAgICAgICAgICAgYm9yZGVyOiAxcHggZGFzaGVkIGZhZGUoQGdyYXktdGV4dCwgNDAlKTtcclxuICAgICAgICAgICAgICAgIGJvcmRlci1yYWRpdXM6IDRweDtcclxuICAgICAgICAgICAgICAgIHBhZGRpbmc6IEBjb250YWluZXItcGFkZGluZztcclxuICAgICAgICAgICAgICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xyXG4gICAgICAgICAgICAgICAgZm9udC1zaXplOiBAZm9udC1zaXplIC0gMTtcclxuICAgICAgICAgICAgICAgIGZvbnQtc3R5bGU6IGl0YWxpYztcclxuICAgICAgICAgICAgICAgIG9wYWNpdHk6IDAuNjtcclxuICAgICAgICAgICAgICAgIHRleHQtYWxpZ246IGNlbnRlcjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgPiAubGF5b3V0LWNoaWxkcmVuIHtcclxuICAgICAgICAgICAgICAgIHBhZGRpbmc6IEBjb250YWluZXItcGFkZGluZztcclxuXHJcbiAgICAgICAgICAgICAgICAvLyBBbGwgYWRqYWNlbnQgbm9uLWNvbnRhaW5lciBjaGlsZHJlbiBuZWVkIHNvbWUgc3BhY2UgYmV0d2Vlbi4uLlxyXG4gICAgICAgICAgICAgICAgPiAubGF5b3V0LWVsZW1lbnQ6bm90KC5sYXlvdXQtY29udGFpbmVyKSArIC5sYXlvdXQtZWxlbWVudDpub3QoLmxheW91dC1jb250YWluZXIpIHtcclxuICAgICAgICAgICAgICAgICAgICBtYXJnaW4tdG9wOiBAY29udGVudC1zcGFjaW5nO1xyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIC8vIC4uLiBleGNlcHQgd2hlbiBqUXVlcnkgVUkgc29ydGFibGUgaGVscGVyIGlzIHRoZSBmaXJzdCBlbGVtZW50IChiZWNhdXNlIHRoYXQgb25lIGlzIGFic29sdXRlbHkgcG9zaXRpb25lZCBhbmQgXCJmbG9hdGluZ1wiKS5cclxuICAgICAgICAgICAgICAgID4gLnVpLXNvcnRhYmxlLWhlbHBlcjpmaXJzdC1jaGlsZCArIC5sYXlvdXQtZWxlbWVudDpub3QoLmxheW91dC1jb250YWluZXIpIHtcclxuICAgICAgICAgICAgICAgICAgICBtYXJnaW4tdG9wOiAwO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAmLmxheW91dC1jb250YWluZXItZW1wdHkge1xyXG4gICAgICAgICAgICAgICAgPiAubGF5b3V0LWNvbnRhaW5lci1jaGlsZHJlbi1wbGFjZWhvbGRlciB7XHJcbiAgICAgICAgICAgICAgICAgICAgZGlzcGxheTogZmxleDsgLy8gVG8gcmV2ZWFsLlxyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgID4gLmxheW91dC1jaGlsZHJlbiB7XHJcbiAgICAgICAgICAgICAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xyXG4gICAgICAgICAgICAgICAgICAgIHRvcDogMDtcclxuICAgICAgICAgICAgICAgICAgICByaWdodDogMDtcclxuICAgICAgICAgICAgICAgICAgICBib3R0b206IDA7XHJcbiAgICAgICAgICAgICAgICAgICAgbGVmdDogMDtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAmOm5vdCgubGF5b3V0LWVkaXRvci1kcmFnZ2luZykge1xyXG4gICAgICAgIC5sYXlvdXQtY29udGFpbmVyLmxheW91dC1lbGVtZW50LWZvY3VzZWQgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY2hpbGRyZW4ge1xyXG4gICAgICAgICAgICA+IC5sYXlvdXQtZWxlbWVudDpub3QoLmxheW91dC1lbGVtZW50LWFjdGl2ZSkge1xyXG4gICAgICAgICAgICAgICAgYm9yZGVyOiAxcHggZGFzaGVkIGZhZGUoQGdyYXktdGV4dCwgNjAlKTtcclxuXHJcbiAgICAgICAgICAgICAgICA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIHtcclxuICAgICAgICAgICAgICAgICAgICBtYXJnaW46IC0xcHg7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgID4gLmxheW91dC1jb250YWluZXIgKyAubGF5b3V0LWNvbnRhaW5lcjpub3QoLmxheW91dC1lbGVtZW50LWFjdGl2ZSkge1xyXG4gICAgICAgICAgICAgICAgYm9yZGVyLXRvcDogMDtcclxuXHJcbiAgICAgICAgICAgICAgICA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIHtcclxuICAgICAgICAgICAgICAgICAgICBtYXJnaW4tdG9wOiAwO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcbiIsIu+7v0BpbXBvcnQgXCJWYXJpYWJsZXMubGVzc1wiO1xyXG5cclxuLmxheW91dC1lZGl0b3Ige1xyXG4gICAgLmxheW91dC1jYW52YXMge1xyXG4gICAgICAgICNkdW1teSB7IC8vIE9ubHkgYWRkZWQgYmVjYXVzZSBXRSBkb2Vzbid0IGNvbXBpbGUgaWYgdGhlcmUgYXJlIG5vIHJ1bGVzLlxyXG4gICAgICAgICAgICBkaXNwbGF5OiBub25lO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufSIsIu+7v0BpbXBvcnQgXCJWYXJpYWJsZXMubGVzc1wiO1xyXG5cclxuLmxheW91dC1lZGl0b3Ige1xyXG4gICAgLmxheW91dC1yb3cge1xyXG4gICAgICAgICYubGF5b3V0LWVsZW1lbnQtZm9jdXNlZDpub3QoLmxheW91dC1lbGVtZW50LWRyb3B0YXJnZXQpID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNoaWxkcmVuIHtcclxuICAgICAgICAgICAgPiAubGF5b3V0LWVsZW1lbnQ6bm90KC5sYXlvdXQtZWxlbWVudC1hY3RpdmUpIHtcclxuICAgICAgICAgICAgICAgIGJvcmRlci10b3A6IDFweCBkYXNoZWQgZmFkZShAZ3JheS10ZXh0LCA2MCUpICFpbXBvcnRhbnQ7XHJcbiAgICAgICAgICAgICAgICA+IC5sYXlvdXQtZWxlbWVudC13cmFwcGVyIHtcclxuICAgICAgICAgICAgICAgICAgICBtYXJnaW4tdG9wOiAtMXB4ICFpbXBvcnRhbnQ7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgID4gLmxheW91dC1lbGVtZW50ICsgLmxheW91dC1lbGVtZW50Om5vdCgubGF5b3V0LWVsZW1lbnQtYWN0aXZlKSB7XHJcbiAgICAgICAgICAgICAgICBib3JkZXItbGVmdDogMCAhaW1wb3J0YW50O1xyXG4gICAgICAgICAgICAgICAgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciB7XHJcbiAgICAgICAgICAgICAgICAgICAgbWFyZ2luLWxlZnQ6IDAgIWltcG9ydGFudDtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxufSIsIu+7v0BpbXBvcnQgXCJWYXJpYWJsZXMubGVzc1wiO1xyXG5cclxuLmxheW91dC1lZGl0b3Ige1xyXG4gICAgLmxheW91dC1jb2x1bW4ge1xyXG4gICAgICAgID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIge1xyXG4gICAgICAgICAgICA+IC5sYXlvdXQtY29sdW1uLXJlc2l6ZS1iYXIge1xyXG4gICAgICAgICAgICAgICAgZGlzcGxheTogbm9uZTtcclxuICAgICAgICAgICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgICAgICAgICAgICAgIHotaW5kZXg6IDMwO1xyXG4gICAgICAgICAgICAgICAgdG9wOiAwO1xyXG4gICAgICAgICAgICAgICAgd2lkdGg6IDE2cHg7XHJcbiAgICAgICAgICAgICAgICBoZWlnaHQ6IDEwMCU7XHJcbiAgICAgICAgICAgICAgICBjdXJzb3I6IGNvbC1yZXNpemU7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgID4gLmxheW91dC1jb2x1bW4tcmVzaXplLWJhci1sZWZ0IHtcclxuICAgICAgICAgICAgICAgIGxlZnQ6IC02cHg7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgID4gLmxheW91dC1jb2x1bW4tcmVzaXplLWJhci1yaWdodCB7XHJcbiAgICAgICAgICAgICAgICByaWdodDogLTZweDtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgJi5sYXlvdXQtZWxlbWVudC1mb2N1c2VkID4gLmxheW91dC1lbGVtZW50LXdyYXBwZXIgPiAubGF5b3V0LWNvbHVtbi1yZXNpemUtYmFyIHtcclxuICAgICAgICAgICAgZGlzcGxheTogYmxvY2s7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcbiIsIu+7v0BpbXBvcnQgXCJWYXJpYWJsZXMubGVzc1wiO1xyXG5AaW1wb3J0IFwiUmVzZXQubGVzc1wiO1xyXG5cclxuLmxheW91dC1lZGl0b3Ige1xyXG4gICAgLmxheW91dC1jb250ZW50LCAubGF5b3V0LWh0bWwge1xyXG4gICAgICAgIG1pbi1oZWlnaHQ6IDFlbTtcclxuXHJcbiAgICAgICAgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciB7XHJcbiAgICAgICAgICAgIC5sYXlvdXQtY29udGVudC1tYXJrdXAge1xyXG5cclxuICAgICAgICAgICAgICAgIHBhZGRpbmc6IDJweDtcclxuICAgICAgICAgICAgICAgIG92ZXJmbG93LXg6IGhpZGRlbjtcclxuICAgICAgICAgICAgICAgIGxpbmUtaGVpZ2h0OiBub3JtYWw7XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gUmVzZXQgdG8gSFRNTDUgVzNDIHN0YW5kYXJkIGRlZmF1bHQgc3R5bGluZyB3aXRoaW4gY29udGVudC5cclxuICAgICAgICAgICAgICAgIC5yZXNldCgpO1xyXG5cclxuICAgICAgICAgICAgICAgID4gKjpmaXJzdC1jaGlsZCB7XHJcbiAgICAgICAgICAgICAgICAgICAgbWFyZ2luLXRvcDogMCAhaW1wb3J0YW50OyAvLyBJbXBvcnRhbnQgYmVjYXVzZSBzaXRlLmNzcyBvZiB0aGUgYWRtaW4gdGhlbWUgc3R5bGVzIGhlYWRpbmcgbWFyZ2lucyB3aXRoIGEgdmVyeSBoaWdoIHNwZWNpZmljaXR5LlxyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgID4gKjpsYXN0LWNoaWxkIHtcclxuICAgICAgICAgICAgICAgICAgICBtYXJnaW4tYm90dG9tOiAwICFpbXBvcnRhbnQ7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICYubGF5b3V0LWNvbnRlbnQtaW1hZ2UsICYubGF5b3V0LWNvbnRlbnQtdmVjdG9yLWltYWdlIHtcclxuICAgICAgICAgICAgPiAubGF5b3V0LWVsZW1lbnQtd3JhcHBlciA+IC5sYXlvdXQtY29udGVudC1tYXJrdXAgPiBpbWcge1xyXG4gICAgICAgICAgICAgICAgZGlzcGxheTogYmxvY2s7XHJcbiAgICAgICAgICAgICAgICB3aWR0aDogMTAwJTtcclxuICAgICAgICAgICAgICAgIG1heC13aWR0aDogMTAwJTtcclxuICAgICAgICAgICAgICAgIGhlaWdodDogYXV0bztcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAuaW1nLXJlc3BvbnNpdmUsIC5pbWctcmVzcG9uc2l2ZSBpbWcge1xyXG4gICAgICAgIGRpc3BsYXk6IGJsb2NrO1xyXG4gICAgICAgIHdpZHRoOiAxMDAlO1xyXG4gICAgICAgIG1heC13aWR0aDogMTAwJTtcclxuICAgICAgICBoZWlnaHQ6IGF1dG87XHJcbiAgICB9XHJcbn1cclxuIiwi77u/LnJlc2V0KCkge1xyXG5cclxuICAgICoge1xyXG4gICAgICAgIG1hcmdpbjogMDtcclxuICAgICAgICBwYWRkaW5nOiAwO1xyXG4gICAgICAgIGJveC1zaXppbmc6IGNvbnRlbnQtYm94O1xyXG4gICAgfVxyXG5cclxuICAgIGFkZHJlc3MsIGJsb2NrcXVvdGUsIGNlbnRlciwgZGl2LCBmaWd1cmUsIGZpZ2NhcHRpb24sIGZvb3RlciwgZm9ybSxcclxuICAgIGhlYWRlciwgaHIsIGxlZ2VuZCwgbGlzdGluZywgcCwgcGxhaW50ZXh0LCBwcmUsIHhtcCB7XHJcbiAgICAgICAgZGlzcGxheTogYmxvY2s7XHJcbiAgICB9XHJcblxyXG4gICAgYmxvY2txdW90ZSwgZmlndXJlLCBsaXN0aW5nLCBwLCBwbGFpbnRleHQsIHByZSwgeG1wIHtcclxuICAgICAgICBtYXJnaW4tdG9wOiAxZW07XHJcbiAgICAgICAgbWFyZ2luLWJvdHRvbTogMWVtO1xyXG4gICAgfVxyXG5cclxuICAgIGJsb2NrcXVvdGUsIGZpZ3VyZSB7XHJcbiAgICAgICAgbWFyZ2luLWxlZnQ6IDQwcHg7XHJcbiAgICAgICAgbWFyZ2luLXJpZ2h0OiA0MHB4O1xyXG4gICAgfVxyXG5cclxuICAgIGFkZHJlc3Mge1xyXG4gICAgICAgIGZvbnQtc3R5bGU6IGl0YWxpYztcclxuICAgIH1cclxuXHJcbiAgICBsaXN0aW5nLCBwbGFpbnRleHQsIHByZSwgeG1wIHtcclxuICAgICAgICBmb250LWZhbWlseTogbW9ub3NwYWNlO1xyXG4gICAgICAgIHdoaXRlLXNwYWNlOiBwcmU7XHJcbiAgICB9XHJcblxyXG4gICAgY2l0ZSwgZGZuLCBlbSwgaSwgdmFyIHtcclxuICAgICAgICBmb250LXN0eWxlOiBpdGFsaWM7XHJcbiAgICB9XHJcblxyXG4gICAgYiwgc3Ryb25nIHtcclxuICAgICAgICBmb250LXdlaWdodDogYm9sZGVyO1xyXG4gICAgfVxyXG5cclxuICAgIGNvZGUsIGtiZCwgc2FtcCwgdHQge1xyXG4gICAgICAgIGZvbnQtZmFtaWx5OiBtb25vc3BhY2U7XHJcbiAgICB9XHJcblxyXG4gICAgYmlnIHtcclxuICAgICAgICBmb250LXNpemU6IGxhcmdlcjtcclxuICAgIH1cclxuXHJcbiAgICBzbWFsbCB7XHJcbiAgICAgICAgZm9udC1zaXplOiBzbWFsbGVyO1xyXG4gICAgfVxyXG5cclxuICAgIHN1YiB7XHJcbiAgICAgICAgdmVydGljYWwtYWxpZ246IHN1YjtcclxuICAgIH1cclxuXHJcbiAgICBzdXAge1xyXG4gICAgICAgIHZlcnRpY2FsLWFsaWduOiBzdXBlcjtcclxuICAgIH1cclxuXHJcbiAgICBzdWIsIHN1cCB7XHJcbiAgICAgICAgbGluZS1oZWlnaHQ6IG5vcm1hbDtcclxuICAgICAgICBmb250LXNpemU6IHNtYWxsZXI7XHJcbiAgICB9XHJcblxyXG5cclxuICAgIHJ1Ynkge1xyXG4gICAgICAgIGRpc3BsYXk6IHJ1Ynk7XHJcbiAgICB9XHJcblxyXG4gICAgcmIge1xyXG4gICAgICAgIGRpc3BsYXk6IHJ1YnktYmFzZTtcclxuICAgICAgICB3aGl0ZS1zcGFjZTogbm93cmFwO1xyXG4gICAgfVxyXG5cclxuICAgIHJ0IHtcclxuICAgICAgICBkaXNwbGF5OiBydWJ5LXRleHQ7XHJcbiAgICAgICAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcclxuICAgICAgICBmb250LXNpemU6IDUwJTtcclxuICAgICAgICBmb250LXZhcmlhbnQtZWFzdC1hc2lhbjogcnVieTtcclxuICAgICAgICB0ZXh0LWVtcGhhc2lzOiBub25lO1xyXG4gICAgfVxyXG5cclxuICAgIHJiYyB7XHJcbiAgICAgICAgZGlzcGxheTogcnVieS1iYXNlLWNvbnRhaW5lcjtcclxuICAgIH1cclxuXHJcbiAgICBydGMge1xyXG4gICAgICAgIGRpc3BsYXk6IHJ1YnktdGV4dC1jb250YWluZXI7XHJcbiAgICB9XHJcblxyXG4gICAgcnVieSwgcmIsIHJ0LCByYmMsIHJ0YyB7XHJcbiAgICAgICAgdW5pY29kZS1iaWRpOiBpc29sYXRlO1xyXG4gICAgfVxyXG5cclxuXHJcbiAgICA6bGluayB7XHJcbiAgICAgICAgY29sb3I6ICMwMDAwRUU7XHJcbiAgICB9XHJcblxyXG4gICAgOnZpc2l0ZWQge1xyXG4gICAgICAgIGNvbG9yOiAjNTUxQThCO1xyXG4gICAgfVxyXG5cclxuICAgIDpsaW5rLCA6dmlzaXRlZCB7XHJcbiAgICAgICAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7XHJcbiAgICB9XHJcblxyXG4gICAgYTpsaW5rW3JlbH49aGVscF0sIGE6dmlzaXRlZFtyZWx+PWhlbHBdLFxyXG4gICAgYXJlYTpsaW5rW3JlbH49aGVscF0sIGFyZWE6dmlzaXRlZFtyZWx+PWhlbHBdIHtcclxuICAgICAgICBjdXJzb3I6IGhlbHA7XHJcbiAgICB9XHJcblxyXG4gICAgOmZvY3VzIHtcclxuICAgICAgICBvdXRsaW5lOiBhdXRvO1xyXG4gICAgfVxyXG5cclxuICAgIG1hcmsge1xyXG4gICAgICAgIGJhY2tncm91bmQ6IHllbGxvdztcclxuICAgICAgICBjb2xvcjogYmxhY2s7XHJcbiAgICB9XHJcbiAgICAvKiB0aGlzIGNvbG9yIGlzIGp1c3QgYSBzdWdnZXN0aW9uIGFuZCBjYW4gYmUgY2hhbmdlZCBiYXNlZCBvbiBpbXBsZW1lbnRhdGlvbiBmZWVkYmFjayAqL1xyXG4gICAgYWJiclt0aXRsZV0sIGFjcm9ueW1bdGl0bGVdIHtcclxuICAgICAgICB0ZXh0LWRlY29yYXRpb246IGRvdHRlZCB1bmRlcmxpbmU7XHJcbiAgICB9XHJcblxyXG4gICAgaW5zLCB1IHtcclxuICAgICAgICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTtcclxuICAgIH1cclxuXHJcbiAgICBkZWwsIHMsIHN0cmlrZSB7XHJcbiAgICAgICAgdGV4dC1kZWNvcmF0aW9uOiBsaW5lLXRocm91Z2g7XHJcbiAgICB9XHJcblxyXG4gICAgYmxpbmsge1xyXG4gICAgICAgIHRleHQtZGVjb3JhdGlvbjogYmxpbms7XHJcbiAgICB9XHJcblxyXG4gICAgcTo6YmVmb3JlIHtcclxuICAgICAgICBjb250ZW50OiBvcGVuLXF1b3RlO1xyXG4gICAgfVxyXG5cclxuICAgIHE6OmFmdGVyIHtcclxuICAgICAgICBjb250ZW50OiBjbG9zZS1xdW90ZTtcclxuICAgIH1cclxuXHJcbiAgICBicjo6YmVmb3JlIHtcclxuICAgICAgICBjb250ZW50OiAnXFxBJztcclxuICAgICAgICB3aGl0ZS1zcGFjZTogcHJlO1xyXG4gICAgfVxyXG4gICAgLyogdGhpcyBhbHNvIGhhcyBiaWRpIGltcGxpY2F0aW9ucyAqL1xyXG4gICAgbm9iciB7XHJcbiAgICAgICAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcclxuICAgIH1cclxuXHJcbiAgICB3YnIge1xyXG4gICAgICAgIGNvbnRlbnQ6ICdcXDIwMEInO1xyXG4gICAgfVxyXG4gICAgLyogdGhpcyBhbHNvIGhhcyBiaWRpIGltcGxpY2F0aW9ucyAqL1xyXG4gICAgbm9iciB3YnIge1xyXG4gICAgICAgIHdoaXRlLXNwYWNlOiBub3JtYWw7XHJcbiAgICB9XHJcblxyXG4gICAgYXJ0aWNsZSwgYXNpZGUsIGgxLCBoMiwgaDMsIGg0LCBoNSwgaDYsIGhncm91cCwgbmF2LCBzZWN0aW9uIHtcclxuICAgICAgICBkaXNwbGF5OiBibG9jaztcclxuICAgIH1cclxuXHJcbiAgICBoMSB7XHJcbiAgICAgICAgbWFyZ2luLXRvcDogMC42N2VtO1xyXG4gICAgICAgIG1hcmdpbi1ib3R0b206IDAuNjdlbTtcclxuICAgICAgICBmb250LXNpemU6IDIuMDBlbTtcclxuICAgICAgICBmb250LXdlaWdodDogYm9sZDtcclxuICAgIH1cclxuXHJcbiAgICBoMiB7XHJcbiAgICAgICAgbWFyZ2luLXRvcDogMC44M2VtO1xyXG4gICAgICAgIG1hcmdpbi1ib3R0b206IDAuODNlbTtcclxuICAgICAgICBmb250LXNpemU6IDEuNTBlbTtcclxuICAgICAgICBmb250LXdlaWdodDogYm9sZDtcclxuICAgIH1cclxuXHJcbiAgICBoMyB7XHJcbiAgICAgICAgbWFyZ2luLXRvcDogMS4wMGVtO1xyXG4gICAgICAgIG1hcmdpbi1ib3R0b206IDEuMDBlbTtcclxuICAgICAgICBmb250LXNpemU6IDEuMTdlbTtcclxuICAgICAgICBmb250LXdlaWdodDogYm9sZDtcclxuICAgIH1cclxuXHJcbiAgICBoNCB7XHJcbiAgICAgICAgbWFyZ2luLXRvcDogMS4zM2VtO1xyXG4gICAgICAgIG1hcmdpbi1ib3R0b206IDEuMzNlbTtcclxuICAgICAgICBmb250LXNpemU6IDEuMDBlbTtcclxuICAgICAgICBmb250LXdlaWdodDogYm9sZDtcclxuICAgIH1cclxuXHJcbiAgICBoNSB7XHJcbiAgICAgICAgbWFyZ2luLXRvcDogMS42N2VtO1xyXG4gICAgICAgIG1hcmdpbi1ib3R0b206IDEuNjdlbTtcclxuICAgICAgICBmb250LXNpemU6IDAuODNlbTtcclxuICAgICAgICBmb250LXdlaWdodDogYm9sZDtcclxuICAgIH1cclxuXHJcbiAgICBoNiB7XHJcbiAgICAgICAgbWFyZ2luLXRvcDogMi4zM2VtO1xyXG4gICAgICAgIG1hcmdpbi1ib3R0b206IDIuMzNlbTtcclxuICAgICAgICBmb250LXNpemU6IDAuNjdlbTtcclxuICAgICAgICBmb250LXdlaWdodDogYm9sZDtcclxuICAgIH1cclxuXHJcbiAgICBkaXIsIGRkLCBkbCwgZHQsIG9sLCB1bCB7XHJcbiAgICAgICAgZGlzcGxheTogYmxvY2s7XHJcbiAgICB9XHJcblxyXG4gICAgbGkge1xyXG4gICAgICAgIGRpc3BsYXk6IGxpc3QtaXRlbTtcclxuICAgIH1cclxuXHJcbiAgICBkaXIsIGRsLCBvbCwgdWwge1xyXG4gICAgICAgIG1hcmdpbi10b3A6IDFlbTtcclxuICAgICAgICBtYXJnaW4tYm90dG9tOiAxZW07XHJcbiAgICB9XHJcblxyXG4gICAgICAgIGRpciBkaXIsIGRpciBkbCwgZGlyIG9sLCBkaXIgdWwsXHJcbiAgICAgICAgZGwgZGlyLCBkbCBkbCwgZGwgb2wsIGRsIHVsLFxyXG4gICAgICAgIG9sIGRpciwgb2wgZGwsIG9sIG9sLCBvbCB1bCxcclxuICAgICAgICB1bCBkaXIsIHVsIGRsLCB1bCBvbCwgdWwgdWwge1xyXG4gICAgICAgICAgICBtYXJnaW4tdG9wOiAwO1xyXG4gICAgICAgICAgICBtYXJnaW4tYm90dG9tOiAwO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICBkZCB7XHJcbiAgICAgICAgbWFyZ2luLWxlZnQ6IDQwcHg7XHJcbiAgICB9XHJcbiAgICAvKiBMVFItc3BlY2lmaWM6IHVzZSAnbWFyZ2luLXJpZ2h0JyBmb3IgcnRsIGVsZW1lbnRzICovXHJcbiAgICBkaXIsIG9sLCB1bCB7XHJcbiAgICAgICAgcGFkZGluZy1sZWZ0OiA0MHB4O1xyXG4gICAgfVxyXG4gICAgLyogTFRSLXNwZWNpZmljOiB1c2UgJ3BhZGRpbmctcmlnaHQnIGZvciBydGwgZWxlbWVudHMgKi9cclxuICAgIG9sIHtcclxuICAgICAgICBsaXN0LXN0eWxlLXR5cGU6IGRlY2ltYWw7XHJcbiAgICB9XHJcblxyXG4gICAgZGlyLCB1bCB7XHJcbiAgICAgICAgbGlzdC1zdHlsZS10eXBlOiBkaXNjO1xyXG4gICAgfVxyXG5cclxuICAgICAgICBkaXIgZGlyLCBkaXIgdWwsXHJcbiAgICAgICAgb2wgZGlyLCBvbCB1bCxcclxuICAgICAgICB1bCBkaXIsIHVsIHVsIHtcclxuICAgICAgICAgICAgbGlzdC1zdHlsZS10eXBlOiBjaXJjbGU7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgZGlyIGRpciBkaXIsIGRpciBkaXIgdWwsXHJcbiAgICAgICAgICAgIGRpciBvbCBkaXIsIGRpciBvbCB1bCxcclxuICAgICAgICAgICAgZGlyIHVsIGRpciwgZGlyIHVsIHVsLFxyXG4gICAgICAgICAgICBvbCBkaXIgZGlyLCBvbCBkaXIgdWwsXHJcbiAgICAgICAgICAgIG9sIG9sIGRpciwgb2wgb2wgdWwsXHJcbiAgICAgICAgICAgIG9sIHVsIGRpciwgb2wgdWwgdWwsXHJcbiAgICAgICAgICAgIHVsIGRpciBkaXIsIHVsIGRpciB1bCxcclxuICAgICAgICAgICAgdWwgb2wgZGlyLCB1bCBvbCB1bCxcclxuICAgICAgICAgICAgdWwgdWwgZGlyLCB1bCB1bCB1bCB7XHJcbiAgICAgICAgICAgICAgICBsaXN0LXN0eWxlLXR5cGU6IHNxdWFyZTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgIHRhYmxlIHtcclxuICAgICAgICBkaXNwbGF5OiB0YWJsZTtcclxuICAgIH1cclxuXHJcbiAgICBjYXB0aW9uIHtcclxuICAgICAgICBkaXNwbGF5OiB0YWJsZS1jYXB0aW9uO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbGdyb3VwLCBjb2xncm91cFtoaWRkZW5dIHtcclxuICAgICAgICBkaXNwbGF5OiB0YWJsZS1jb2x1bW4tZ3JvdXA7XHJcbiAgICB9XHJcblxyXG4gICAgY29sLCBjb2xbaGlkZGVuXSB7XHJcbiAgICAgICAgZGlzcGxheTogdGFibGUtY29sdW1uO1xyXG4gICAgfVxyXG5cclxuICAgIHRoZWFkLCB0aGVhZFtoaWRkZW5dIHtcclxuICAgICAgICBkaXNwbGF5OiB0YWJsZS1oZWFkZXItZ3JvdXA7XHJcbiAgICB9XHJcblxyXG4gICAgdGJvZHksIHRib2R5W2hpZGRlbl0ge1xyXG4gICAgICAgIGRpc3BsYXk6IHRhYmxlLXJvdy1ncm91cDtcclxuICAgIH1cclxuXHJcbiAgICB0Zm9vdCwgdGZvb3RbaGlkZGVuXSB7XHJcbiAgICAgICAgZGlzcGxheTogdGFibGUtZm9vdGVyLWdyb3VwO1xyXG4gICAgfVxyXG5cclxuICAgIHRyLCB0cltoaWRkZW5dIHtcclxuICAgICAgICBkaXNwbGF5OiB0YWJsZS1yb3c7XHJcbiAgICB9XHJcblxyXG4gICAgdGQsIHRoLCB0ZFtoaWRkZW5dLCB0aFtoaWRkZW5dIHtcclxuICAgICAgICBkaXNwbGF5OiB0YWJsZS1jZWxsO1xyXG4gICAgfVxyXG5cclxuICAgICAgICBjb2xncm91cFtoaWRkZW5dLCBjb2xbaGlkZGVuXSwgdGhlYWRbaGlkZGVuXSwgdGJvZHlbaGlkZGVuXSxcclxuICAgICAgICB0Zm9vdFtoaWRkZW5dLCB0cltoaWRkZW5dLCB0ZFtoaWRkZW5dLCB0aFtoaWRkZW5dIHtcclxuICAgICAgICAgICAgdmlzaWJpbGl0eTogY29sbGFwc2U7XHJcbiAgICAgICAgfVxyXG5cclxuICAgIHRhYmxlIHtcclxuICAgICAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG4gICAgICAgIGJvcmRlci1zcGFjaW5nOiAycHg7XHJcbiAgICAgICAgYm9yZGVyLWNvbGxhcHNlOiBzZXBhcmF0ZTtcclxuICAgICAgICB0ZXh0LWluZGVudDogaW5pdGlhbDtcclxuICAgIH1cclxuXHJcbiAgICB0ZCwgdGgge1xyXG4gICAgICAgIHBhZGRpbmc6IDFweDtcclxuICAgIH1cclxuXHJcbiAgICB0aCB7XHJcbiAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7XHJcbiAgICB9XHJcblxyXG4gICAgdGhlYWQsIHRib2R5LCB0Zm9vdCwgdGFibGUgPiB0ciB7XHJcbiAgICAgICAgdmVydGljYWwtYWxpZ246IG1pZGRsZTtcclxuICAgIH1cclxuXHJcbiAgICB0ciwgdGQsIHRoIHtcclxuICAgICAgICB2ZXJ0aWNhbC1hbGlnbjogaW5oZXJpdDtcclxuICAgIH1cclxuXHJcbiAgICB0YWJsZSwgdGQsIHRoIHtcclxuICAgICAgICBib3JkZXItY29sb3I6IGdyYXk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhlYWQsIHRib2R5LCB0Zm9vdCwgdHIge1xyXG4gICAgICAgIGJvcmRlci1jb2xvcjogaW5oZXJpdDtcclxuICAgIH1cclxuICAgIC8qdGFibGVbcnVsZXM9bm9uZSBpXSwgdGFibGVbcnVsZXM9Z3JvdXBzIGldLCB0YWJsZVtydWxlcz1yb3dzIGldLFxyXG50YWJsZVtydWxlcz1jb2xzIGldLCB0YWJsZVtydWxlcz1hbGwgaV0sIHRhYmxlW2ZyYW1lPXZvaWQgaV0sXHJcbnRhYmxlW2ZyYW1lPWFib3ZlIGldLCB0YWJsZVtmcmFtZT1iZWxvdyBpXSwgdGFibGVbZnJhbWU9aHNpZGVzIGldLFxyXG50YWJsZVtmcmFtZT1saHMgaV0sIHRhYmxlW2ZyYW1lPXJocyBpXSwgdGFibGVbZnJhbWU9dnNpZGVzIGldLFxyXG50YWJsZVtmcmFtZT1ib3ggaV0sIHRhYmxlW2ZyYW1lPWJvcmRlciBpXSxcclxudGFibGVbcnVsZXM9bm9uZSBpXSA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPW5vbmUgaV0gPiB0ciA+IHRoLFxyXG50YWJsZVtydWxlcz1ncm91cHMgaV0gPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1ncm91cHMgaV0gPiB0ciA+IHRoLFxyXG50YWJsZVtydWxlcz1yb3dzIGldID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9cm93cyBpXSA+IHRyID4gdGgsXHJcbnRhYmxlW3J1bGVzPWNvbHMgaV0gPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1jb2xzIGldID4gdHIgPiB0aCxcclxudGFibGVbcnVsZXM9YWxsIGldID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9YWxsIGldID4gdHIgPiB0aCxcclxudGFibGVbcnVsZXM9bm9uZSBpXSA+IHRoZWFkID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9bm9uZSBpXSA+IHRoZWFkID4gdHIgPiB0aCxcclxudGFibGVbcnVsZXM9Z3JvdXBzIGldID4gdGhlYWQgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1ncm91cHMgaV0gPiB0aGVhZCA+IHRyID4gdGgsXHJcbnRhYmxlW3J1bGVzPXJvd3MgaV0gPiB0aGVhZCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPXJvd3MgaV0gPiB0aGVhZCA+IHRyID4gdGgsXHJcbnRhYmxlW3J1bGVzPWNvbHMgaV0gPiB0aGVhZCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWNvbHMgaV0gPiB0aGVhZCA+IHRyID4gdGgsXHJcbnRhYmxlW3J1bGVzPWFsbCBpXSA+IHRoZWFkID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9YWxsIGldID4gdGhlYWQgPiB0ciA+IHRoLFxyXG50YWJsZVtydWxlcz1ub25lIGldID4gdGJvZHkgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1ub25lIGldID4gdGJvZHkgPiB0ciA+IHRoLFxyXG50YWJsZVtydWxlcz1ncm91cHMgaV0gPiB0Ym9keSA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWdyb3VwcyBpXSA+IHRib2R5ID4gdHIgPiB0aCxcclxudGFibGVbcnVsZXM9cm93cyBpXSA+IHRib2R5ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9cm93cyBpXSA+IHRib2R5ID4gdHIgPiB0aCxcclxudGFibGVbcnVsZXM9Y29scyBpXSA+IHRib2R5ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9Y29scyBpXSA+IHRib2R5ID4gdHIgPiB0aCxcclxudGFibGVbcnVsZXM9YWxsIGldID4gdGJvZHkgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1hbGwgaV0gPiB0Ym9keSA+IHRyID4gdGgsXHJcbnRhYmxlW3J1bGVzPW5vbmUgaV0gPiB0Zm9vdCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPW5vbmUgaV0gPiB0Zm9vdCA+IHRyID4gdGgsXHJcbnRhYmxlW3J1bGVzPWdyb3VwcyBpXSA+IHRmb290ID4gdHIgPiB0ZCwgdGFibGVbcnVsZXM9Z3JvdXBzIGldID4gdGZvb3QgPiB0ciA+IHRoLFxyXG50YWJsZVtydWxlcz1yb3dzIGldID4gdGZvb3QgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1yb3dzIGldID4gdGZvb3QgPiB0ciA+IHRoLFxyXG50YWJsZVtydWxlcz1jb2xzIGldID4gdGZvb3QgPiB0ciA+IHRkLCB0YWJsZVtydWxlcz1jb2xzIGldID4gdGZvb3QgPiB0ciA+IHRoLFxyXG50YWJsZVtydWxlcz1hbGwgaV0gPiB0Zm9vdCA+IHRyID4gdGQsIHRhYmxlW3J1bGVzPWFsbCBpXSA+IHRmb290ID4gdHIgPiB0aCB7XHJcbiAgICBib3JkZXItY29sb3I6IGJsYWNrO1xyXG59Ki9cclxuICAgIGlucHV0LCBzZWxlY3QsIG9wdGlvbiwgb3B0Z3JvdXAsIGJ1dHRvbiwgdGV4dGFyZWEsIGtleWdlbiB7XHJcbiAgICAgICAgdGV4dC1pbmRlbnQ6IGluaXRpYWw7XHJcbiAgICB9XHJcblxyXG4gICAgdGV4dGFyZWEge1xyXG4gICAgICAgIHdoaXRlLXNwYWNlOiBwcmUtd3JhcDtcclxuICAgIH1cclxuXHJcbiAgICBpbnB1dFt0eXBlPVwicmFkaW9cIl0sIGlucHV0W3R5cGU9XCJjaGVja2JveFwiXSwgaW5wdXRbdHlwZT1cInJlc2V0XCJdLCBpbnB1dFt0eXBlPVwiYnV0dG9uXCJdLFxyXG4gICAgaW5wdXRbdHlwZT1cInN1Ym1pdFwiXSwgc2VsZWN0LCBidXR0b24ge1xyXG4gICAgICAgIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XHJcbiAgICB9XHJcblxyXG4gICAgaW5wdXRbdHlwZT1cImJ1dHRvblwiXSwgYnV0dG9uIHtcclxuICAgICAgICBwYWRkaW5nOiAwLjNlbSAwLjVlbTtcclxuICAgIH1cclxuXHJcbiAgICBociB7XHJcbiAgICAgICAgY29sb3I6IGdyYXk7XHJcbiAgICAgICAgYm9yZGVyLXN0eWxlOiBpbnNldDtcclxuICAgICAgICBib3JkZXItd2lkdGg6IDFweDtcclxuICAgICAgICBtYXJnaW46IDAuNWVtIGF1dG87XHJcbiAgICB9XHJcblxyXG4gICAgZmllbGRzZXQge1xyXG4gICAgICAgIG1hcmdpbi1sZWZ0OiAycHg7XHJcbiAgICAgICAgbWFyZ2luLXJpZ2h0OiAycHg7XHJcbiAgICAgICAgYm9yZGVyOiBncm9vdmUgMnB4IFRocmVlREZhY2U7XHJcbiAgICAgICAgcGFkZGluZzogMC4zNWVtIDAuNjI1ZW0gMC43NWVtO1xyXG4gICAgfVxyXG5cclxuICAgIGxlZ2VuZCB7XHJcbiAgICAgICAgcGFkZGluZy1sZWZ0OiAycHg7XHJcbiAgICAgICAgcGFkZGluZy1yaWdodDogMnB4O1xyXG4gICAgfVxyXG59XHJcbiIsIu+7v0BpbXBvcnQgXCJWYXJpYWJsZXMubGVzc1wiO1xyXG5cclxuYm9keSB7XHJcbiAgICAubGF5b3V0LXRvb2xib3gtaXRlbSB7XHJcbiAgICAgICAgYm9yZGVyOiAxcHggc29saWQgQGdyYXktYm9yZGVyO1xyXG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6ICNmZmY7XHJcbiAgICAgICAgcGFkZGluZzogKEBjb250YWluZXItcGFkZGluZyAtIDMpIEBjb250YWluZXItcGFkZGluZztcclxuICAgICAgICBjdXJzb3I6IGRlZmF1bHQ7XHJcbiAgICAgICAgbGlzdC1zdHlsZS10eXBlOiBub25lO1xyXG5cclxuICAgICAgICBpIHtcclxuICAgICAgICAgICAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xyXG4gICAgICAgICAgICB3aWR0aDogMTZweDtcclxuICAgICAgICAgICAgZm9udDogbm9ybWFsIG5vcm1hbCBub3JtYWwgMTRweC8xIEZvbnRBd2Vzb21lO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgKyAubGF5b3V0LXRvb2xib3gtaXRlbSB7XHJcbiAgICAgICAgICAgIG1hcmdpbi10b3A6IEBjb250YWluZXItcGFkZGluZyAvIDM7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcblxyXG4ubGF5b3V0LWVkaXRvciB7XHJcbiAgICA+IC5sYXlvdXQtdG9vbGJveC13cmFwcGVyIHtcclxuICAgICAgICBwb3NpdGlvbjogc3RpY2t5O1xyXG4gICAgICAgIHRvcDogMXZoO1xyXG4gICAgICAgIHBhZGRpbmctbGVmdDogQGNvbnRhaW5lci1wYWRkaW5nO1xyXG4gICAgICAgIHdpZHRoOiAyMjBweDtcclxuICAgICAgICBvdmVyZmxvdy15OiBhdXRvO1xyXG4gICAgICAgIHNjcm9sbGJhci13aWR0aDogdGhpbjtcclxuICAgICAgICBtaW4taGVpZ2h0OiA0MDBweDtcclxuICAgICAgICBtYXgtaGVpZ2h0OiA5OHZoO1xyXG4gICAgICAgIGhlaWdodDogMTAwJTtcclxuXHJcbiAgICAgICAgPiAubGF5b3V0LXRvb2xib3gge1xyXG4gICAgICAgICAgICBib3JkZXI6IDFweCBzb2xpZCBAZ3JheS1ib3JkZXI7XHJcbiAgICAgICAgICAgIHBhZGRpbmc6IEBjb250YWluZXItcGFkZGluZyAvIDI7XHJcbiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IEBncmF5LWJnO1xyXG5cclxuICAgICAgICAgICAgLmxheW91dC10b29sYm94LWdyb3VwIHtcclxuICAgICAgICAgICAgICAgIC5sYXlvdXQtdG9vbGJveC1ncm91cC1oZWFkaW5nIHtcclxuICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBibG9jaztcclxuICAgICAgICAgICAgICAgICAgICBtYXJnaW4tYm90dG9tOiBAY29udGFpbmVyLXBhZGRpbmcgLyAzO1xyXG4gICAgICAgICAgICAgICAgICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgJjpiZWZvcmUge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoOiAxMHB4O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBtYXJnaW4tcmlnaHQ6IEBjb250YWluZXItcGFkZGluZyAvIDM7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvbnQ6IG5vcm1hbCBub3JtYWwgbm9ybWFsIDE0cHgvMSBGb250QXdlc29tZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb250ZW50OiBcIlxcZjBkN1wiO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAmLmNvbGxhcHNlZCB7XHJcbiAgICAgICAgICAgICAgICAgICAgLmxheW91dC10b29sYm94LWdyb3VwLWhlYWRpbmc6YmVmb3JlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29udGVudDogXCJcXGYwZGFcIjtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIC5sYXlvdXQtdG9vbGJveC1pdGVtcyB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXk6IG5vbmU7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIC5sYXlvdXQtdG9vbGJveC1zZWN0aW9uICsgLmxheW91dC10b29sYm94LXNlY3Rpb24ge1xyXG4gICAgICAgICAgICAgICAgICAgIG1hcmdpbi10b3A6IEBjb250YWluZXItcGFkZGluZyAvIDM7XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgLmxheW91dC10b29sYm94LWl0ZW0ge1xyXG4gICAgICAgICAgICAgICAgICAgIGJvcmRlcjogMXB4IHNvbGlkIEBncmF5LWJvcmRlcjtcclxuICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmO1xyXG4gICAgICAgICAgICAgICAgICAgIHBhZGRpbmc6IChAY29udGFpbmVyLXBhZGRpbmcgLSAzKSBAY29udGFpbmVyLXBhZGRpbmc7XHJcbiAgICAgICAgICAgICAgICAgICAgY3Vyc29yOiBkZWZhdWx0O1xyXG5cclxuICAgICAgICAgICAgICAgICAgICBpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB3aWR0aDogMTZweDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgZm9udDogbm9ybWFsIG5vcm1hbCBub3JtYWwgMTRweC8xIEZvbnRBd2Vzb21lO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgKyAubGF5b3V0LXRvb2xib3gtaXRlbSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG1hcmdpbi10b3A6IEBjb250YWluZXItcGFkZGluZyAvIDM7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICsgLmxheW91dC10b29sYm94LWdyb3VwIHtcclxuICAgICAgICAgICAgICAgICAgICBtYXJnaW4tdG9wOiBAY29udGFpbmVyLXBhZGRpbmcgLyAyO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcbiIsIu+7v0BpbXBvcnQgXCJWYXJpYWJsZXMubGVzc1wiO1xyXG5cclxuLmxheW91dC1lZGl0b3Ige1xyXG4gICAgLmxheW91dC1wb3B1cCB7XHJcbiAgICAgICAgZGlzcGxheTogbm9uZTsgLy8gU2hvd24gb25seSBpbiBhY3RpdmUgb3IgZm9jdXNlZCBzdGF0ZXMuXHJcbiAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xyXG4gICAgICAgIG1hcmdpbjogMDtcclxuICAgICAgICAtbW96LWJveC1zaGFkb3c6IDNweCAzcHggMTFweCAwIHJnYmEoNTAsIDUwLCA1MCwgMC41KTtcclxuICAgICAgICAtd2Via2l0LWJveC1zaGFkb3c6IDNweCAzcHggMTFweCAwIHJnYmEoNTAsIDUwLCA1MCwgMC41KTtcclxuICAgICAgICBib3gtc2hhZG93OiAzcHggM3B4IDExcHggMCByZ2JhKDUwLCA1MCwgNTAsIDAuNSk7XHJcbiAgICAgICAgYm9yZGVyOiAxcHggc29saWQgQGdyYXktYm9yZGVyO1xyXG4gICAgICAgIHBhZGRpbmc6IDJweCAwO1xyXG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6ICNmN2Y3Zjc7XHJcbiAgICAgICAgbGlzdC1zdHlsZTogbm9uZTtcclxuICAgICAgICB6LWluZGV4OiAyMDtcclxuICAgICAgICBjb2xvcjogQGdyYXktdGV4dDtcclxuICAgICAgICB0ZXh0LWFsaWduOiBsZWZ0O1xyXG4gICAgICAgIGN1cnNvcjogZGVmYXVsdDtcclxuICAgICAgICB3aGl0ZS1zcGFjZTogbm93cmFwO1xyXG4gICAgICAgIGxpbmUtaGVpZ2h0OiBub3JtYWw7XHJcbiAgICAgICAgbWluLXdpZHRoOiAzMDBweDtcclxuXHJcbiAgICAgICAgJi53aWRlIHtcclxuICAgICAgICAgICAgd2lkdGg6IDYwMHB4O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLmxheW91dC1wb3B1cC1mbGV4IHtcclxuICAgICAgICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgICAgICAgcGFkZGluZzogMnB4IDVweDtcclxuXHJcbiAgICAgICAgICAgIC5sYXlvdXQtcG9wdXAtY29sdW1uICsgLmxheW91dC1wb3B1cC1jb2x1bW4ge1xyXG4gICAgICAgICAgICAgICAgbWFyZ2luLWxlZnQ6IDRweDtcclxuICAgICAgICAgICAgICAgIGJvcmRlci1sZWZ0OiAxcHggc29saWQgZmFkZShncmF5LCAxNSUpO1xyXG4gICAgICAgICAgICAgICAgcGFkZGluZy1sZWZ0OiA0cHg7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC5sYXlvdXQtcG9wdXAtaXRlbSB7XHJcbiAgICAgICAgICAgIHBhZGRpbmc6IDRweCA2cHg7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAubGF5b3V0LXBvcHVwLWxhYmVsIHtcclxuICAgICAgICAgICAgZm9udC1zaXplOiAwLjllbTtcclxuICAgICAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7XHJcbiAgICAgICAgICAgIGNvbG9yOiBAZ3JheS10ZXh0O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLmxheW91dC1wb3B1cC1hY3Rpb246aG92ZXIge1xyXG4gICAgICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiBAZ3JheS1iZztcclxuICAgICAgICAgICAgY3Vyc29yOiBwb2ludGVyO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLmxheW91dC1wb3B1cC1pbnB1dCB7XHJcbiAgICAgICAgICAgIGlucHV0W3R5cGU9J3RleHQnXSwgdGV4dGFyZWEge1xyXG4gICAgICAgICAgICAgICAgd2lkdGg6IDEwMCU7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgID4gbGFiZWwge1xyXG4gICAgICAgICAgICAgICAgZGlzcGxheTogYmxvY2s7XHJcbiAgICAgICAgICAgICAgICBmb250LXNpemU6IDAuOWVtO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcbiJdfQ== */ diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Styles/LayoutEditor.min.css b/src/Orchard.Web/Modules/Orchard.Layouts/Styles/LayoutEditor.min.css index f57b284635e..a6a57911c93 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Styles/LayoutEditor.min.css +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Styles/LayoutEditor.min.css @@ -1 +1 @@ -.layout-editor-toolbar{-ms-flex-pack:justify;justify-content:space-between;position:relative;top:10px}.layout-editor-toolbar,.layout-editor-toolbar .layout-editor-toolbar-group{display:-ms-flexbox;display:flex}.layout-editor-toolbar .layout-editor-toolbar-group>li+li{margin-left:12px}.layout-editor{display:-ms-flexbox;display:flex;margin-top:1em;font-size:14px;-ms-flex-align:stretch;align-items:stretch}.layout-editor>.layout-canvas-wrapper{-ms-flex-positive:1;flex-grow:1;background-color:#f3f4f5;border:1px solid #e4e5e6}.layout-editor>.layout-canvas-wrapper>.layout-toolbar-container{display:none;margin:12px 12px 0;min-height:71px}.layout-editor>.layout-canvas-wrapper>.layout-toolbar-container>.mce-panel{width:100%!important}.layout-editor>.layout-canvas-wrapper .layout-content>.layout-element-wrapper .layout-content-markup>.layout-placeholder{border:1px dashed #ccc;padding:.2em .4em;background:#e8e8e8}.layout-editor .layout-snippet{background:#e8e8e8}.layout-editor-help-dialog{display:none}.layout-editor-help-dialog .help-row:after,.layout-editor-help-dialog .help-row:before{content:" ";display:table}.layout-editor-help-dialog .help-row:after{clear:both}.layout-editor-help-dialog .help-row>.help-column-full,.layout-editor-help-dialog .help-row>.help-column-half{margin:.5em 0}.layout-editor-help-dialog .help-row>.help-column-half{box-sizing:border-box;float:left;width:50%}.layout-editor-help-dialog .help-row>.help-column-half:nth-child(2n){padding-right:10px;clear:left}.layout-editor-help-dialog .help-row+.help-row{margin-top:1em}.layout-editor-help-dialog code{border-radius:4px;background-color:#f3f4f5;padding:2px 4px;font-family:monospace}.layout-editor-help-dialog p{margin-bottom:.5em;line-height:1.6em}.layout-editor-help-dialog table>tbody>tr>td:first-child{padding-right:10px}.layout-editor .layout-element{position:relative;margin-top:0;margin-right:0;margin-bottom:0;padding:0}.layout-editor .layout-element:not(.layout-column){margin-left:0}.layout-editor .layout-element>.layout-element-wrapper>.layout-panel{display:none;position:absolute;margin:0;z-index:20;height:25px;padding:0 6px;list-style:none;white-space:nowrap;line-height:25px;vertical-align:middle}.layout-editor .layout-element>.layout-element-wrapper>.layout-panel>.layout-panel-item{display:inline-block;height:25px;padding:1px 6px 0}.layout-editor .layout-element>.layout-element-wrapper>.layout-panel>.layout-panel-label{font-size:13px}.layout-editor .layout-element>.layout-element-wrapper>.layout-panel>.layout-panel-action{display:none;width:28px;cursor:pointer;text-align:center}.layout-editor .layout-element>.layout-element-wrapper>.layout-panel-main{top:-27px;left:-2px}.layout-editor li.layout-element{list-style:none}.layout-editor:not(.layout-editor-dragging) .layout-element-active,.layout-editor:not(.layout-editor-dragging) .layout-element-focused{border-width:2px;border-style:solid}.layout-editor:not(.layout-editor-dragging) .layout-element-active>.layout-element-wrapper,.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper{margin:-2px}.layout-editor:not(.layout-editor-dragging) .layout-element-active{border-color:hsla(0,0%,41%,.1)}.layout-editor:not(.layout-editor-dragging) .layout-element-active>.layout-element-wrapper>.layout-panel-main{display:block;z-index:30;background-color:hsla(0,0%,41%,.1)}.layout-editor:not(.layout-editor-dragging) .layout-element-focused{border-color:#648721}.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper>.layout-panel{display:block;background-color:#648721;color:#fefefe}.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper>.layout-panel>.layout-panel-action{display:inline-block}.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper>.layout-panel>.layout-panel-action:hover{background-color:#82b02b}.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper>.layout-panel>.layout-panel-action.disabled{cursor:default;color:hsla(0,0%,100%,.4)}.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper>.layout-panel>.layout-panel-action.disabled:hover{background-color:#648721}.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper>.layout-panel>.layout-panel-action.active{color:#deff42;background-color:#739b26}.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper>.layout-panel>.layout-panel-action.active:hover{background-color:#82b02b}.layout-editor:not(.layout-editor-dragging) .layout-element-selected{background-color:rgba(100,135,33,.08)}.layout-editor .ui-sortable-placeholder{display:none}.layout-editor .layout-element-droptarget{box-shadow:inset 0 0 12px 6px rgba(100,135,33,.5)}.layout-editor .layout-element-droptarget .ui-sortable-placeholder{display:block;visibility:visible!important;min-height:78px;border:2px dashed #648721!important;background-color:rgba(100,135,33,.16)}.layout-editor .media-thumbnail img{max-width:100%;max-height:100%}.layout-editor .layout-container>.layout-element-wrapper>.layout-container-children-placeholder{display:none;-ms-flex-direction:column;flex-direction:column;margin:11px;min-height:80px;border:1px dashed hsla(0,0%,49%,.4);border-radius:4px;padding:12px;-ms-flex-pack:center;justify-content:center;font-size:13px;font-style:italic;opacity:.6;text-align:center}.layout-editor .layout-container>.layout-element-wrapper>.layout-children{padding:12px}.layout-editor .layout-container>.layout-element-wrapper>.layout-children>.layout-element:not(.layout-container)+.layout-element:not(.layout-container){margin-top:12px}.layout-editor .layout-container>.layout-element-wrapper>.layout-children>.ui-sortable-helper:first-child+.layout-element:not(.layout-container){margin-top:0}.layout-editor .layout-container>.layout-element-wrapper.layout-container-empty>.layout-container-children-placeholder{display:-ms-flexbox;display:flex}.layout-editor .layout-container>.layout-element-wrapper.layout-container-empty>.layout-children{position:absolute;top:0;right:0;bottom:0;left:0}.layout-editor:not(.layout-editor-dragging) .layout-container.layout-element-focused>.layout-element-wrapper>.layout-children>.layout-element:not(.layout-element-active){border:1px dashed hsla(0,0%,49%,.6)}.layout-editor:not(.layout-editor-dragging) .layout-container.layout-element-focused>.layout-element-wrapper>.layout-children>.layout-element:not(.layout-element-active)>.layout-element-wrapper{margin:-1px}.layout-editor:not(.layout-editor-dragging) .layout-container.layout-element-focused>.layout-element-wrapper>.layout-children>.layout-container+.layout-container:not(.layout-element-active){border-top:0}.layout-editor:not(.layout-editor-dragging) .layout-container.layout-element-focused>.layout-element-wrapper>.layout-children>.layout-container+.layout-container:not(.layout-element-active)>.layout-element-wrapper{margin-top:0}.layout-editor .layout-canvas #dummy{display:none}.layout-editor .layout-row.layout-element-focused:not(.layout-element-droptarget)>.layout-element-wrapper>.layout-children>.layout-element:not(.layout-element-active){border-top:1px dashed hsla(0,0%,49%,.6)!important}.layout-editor .layout-row.layout-element-focused:not(.layout-element-droptarget)>.layout-element-wrapper>.layout-children>.layout-element:not(.layout-element-active)>.layout-element-wrapper{margin-top:-1px!important}.layout-editor .layout-row.layout-element-focused:not(.layout-element-droptarget)>.layout-element-wrapper>.layout-children>.layout-element+.layout-element:not(.layout-element-active){border-left:0!important}.layout-editor .layout-row.layout-element-focused:not(.layout-element-droptarget)>.layout-element-wrapper>.layout-children>.layout-element+.layout-element:not(.layout-element-active)>.layout-element-wrapper{margin-left:0!important}.layout-editor .layout-column>.layout-element-wrapper>.layout-column-resize-bar{display:none;position:absolute;z-index:30;top:0;width:16px;height:100%;cursor:col-resize}.layout-editor .layout-column>.layout-element-wrapper>.layout-column-resize-bar-left{left:-6px}.layout-editor .layout-column>.layout-element-wrapper>.layout-column-resize-bar-right{right:-6px}.layout-editor .layout-column.layout-element-focused>.layout-element-wrapper>.layout-column-resize-bar{display:block}.layout-editor .layout-content,.layout-editor .layout-html{min-height:1em}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup{padding:2px;overflow-x:hidden;line-height:normal}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup *,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup *{margin:0;padding:0;box-sizing:content-box}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup address,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup blockquote,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup center,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup div,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup figcaption,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup figure,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup footer,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup form,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup header,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup hr,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup legend,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup listing,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup p,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup plaintext,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup pre,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup xmp,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup address,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup blockquote,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup center,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup div,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup figcaption,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup figure,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup footer,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup form,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup header,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup hr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup legend,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup listing,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup p,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup plaintext,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup pre,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup xmp{display:block}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup blockquote,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup figure,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup listing,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup p,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup plaintext,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup pre,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup xmp,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup blockquote,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup figure,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup listing,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup p,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup plaintext,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup pre,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup xmp{margin-top:1em;margin-bottom:1em}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup blockquote,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup figure,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup blockquote,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup figure{margin-left:40px;margin-right:40px}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup address,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup address{font-style:italic}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup listing,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup plaintext,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup pre,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup xmp,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup listing,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup plaintext,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup pre,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup xmp{font-family:monospace;white-space:pre}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup cite,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dfn,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup em,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup i,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup var,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup cite,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dfn,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup em,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup i,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup var{font-style:italic}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup b,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup strong,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup b,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup strong{font-weight:bolder}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup code,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup kbd,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup samp,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tt,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup code,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup kbd,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup samp,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tt{font-family:monospace}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup big,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup big{font-size:larger}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup small,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup small{font-size:smaller}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup sub,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup sub{vertical-align:sub}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup sup,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup sup{vertical-align:super}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup sub,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup sup,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup sub,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup sup{line-height:normal;font-size:smaller}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ruby,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ruby{display:ruby}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rb,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rb{display:ruby-base;white-space:nowrap}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rt,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rt{display:ruby-text;white-space:nowrap;font-size:50%;font-variant-east-asian:ruby;-webkit-text-emphasis:none;text-emphasis:none}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rbc,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rbc{display:ruby-base-container}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rtc,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rtc{display:ruby-text-container}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rb,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rbc,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rt,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rtc,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ruby,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rb,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rbc,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rt,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rtc,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ruby{unicode-bidi:isolate}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup :link,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup :link{color:#00e}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup :visited,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup :visited{color:#551a8b}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup :link,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup :visited,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup :link,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup :visited{text-decoration:underline}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup a:link[rel~=help],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup a:visited[rel~=help],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup area:link[rel~=help],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup area:visited[rel~=help],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup a:link[rel~=help],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup a:visited[rel~=help],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup area:link[rel~=help],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup area:visited[rel~=help]{cursor:help}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup :focus,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup :focus{outline:auto}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup mark,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup mark{background:#ff0;color:#000}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup abbr[title],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup acronym[title],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup abbr[title],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup acronym[title]{text-decoration:dotted underline}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ins,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup u,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ins,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup u{text-decoration:underline}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup del,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup s,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup strike,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup del,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup s,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup strike{text-decoration:line-through}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup blink,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup blink{text-decoration:blink}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup q:before,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup q:before{content:open-quote}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup q:after,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup q:after{content:close-quote}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup br:before,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup br:before{content:"\A";white-space:pre}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup nobr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup nobr{white-space:nowrap}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup wbr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup wbr{content:"\200B"}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup nobr wbr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup nobr wbr{white-space:normal}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup article,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup aside,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h1,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h2,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h3,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h4,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h5,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h6,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup hgroup,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup nav,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup section,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup article,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup aside,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h1,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h2,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h3,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h4,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h5,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h6,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup hgroup,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup nav,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup section{display:block}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h1,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h1{margin-top:.67em;margin-bottom:.67em;font-size:2em;font-weight:700}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h2,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h2{margin-top:.83em;margin-bottom:.83em;font-size:1.5em;font-weight:700}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h3,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h3{margin-top:1em;margin-bottom:1em;font-size:1.17em;font-weight:700}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h4,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h4{margin-top:1.33em;margin-bottom:1.33em;font-size:1em;font-weight:700}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h5,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h5{margin-top:1.67em;margin-bottom:1.67em;font-size:.83em;font-weight:700}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h6,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h6{margin-top:2.33em;margin-bottom:2.33em;font-size:.67em;font-weight:700}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dd,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dl,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dt,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dd,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dl,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dt,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul{display:block}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup li,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup li{display:list-item}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dl,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dl,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul{margin-top:1em;margin-bottom:1em}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir dl,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir ol,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dl dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dl dl,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dl ol,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dl ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol dl,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol ol,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul dl,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul ol,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir dl,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dl dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dl dl,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dl ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dl ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol dl,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul dl,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul ul{margin-top:0;margin-bottom:0}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dd,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dd{margin-left:40px}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul{padding-left:40px}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol{list-style-type:decimal}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul{list-style-type:disc}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul ul{list-style-type:circle}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir dir dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir dir ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir ol dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir ol ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir ul dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir ul ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol dir dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol dir ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol ol dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol ol ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol ul dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol ul ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul dir dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul dir ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul ol dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul ol ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul ul dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul ul ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir dir dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir dir ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir ol dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir ol ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir ul dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir ul ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol dir dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol dir ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol ol dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol ol ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol ul dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol ul ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul dir dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul dir ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul ol dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul ol ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul ul dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul ul ul{list-style-type:square}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup table,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup table{display:table}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup caption,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup caption{display:table-caption}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup colgroup,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup colgroup[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup colgroup,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup colgroup[hidden]{display:table-column-group}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup col,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup col[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup col,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup col[hidden]{display:table-column}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup thead,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup thead[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup thead,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup thead[hidden]{display:table-header-group}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tbody,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tbody[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tbody,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tbody[hidden]{display:table-row-group}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tfoot,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tfoot[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tfoot,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tfoot[hidden]{display:table-footer-group}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tr,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tr[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tr[hidden]{display:table-row}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup td[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup th,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup th[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup td[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup th,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup th[hidden]{display:table-cell}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup col[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup colgroup[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tbody[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup td[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tfoot[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup th[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup thead[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tr[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup col[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup colgroup[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tbody[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup td[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tfoot[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup th[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup thead[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tr[hidden]{visibility:collapse}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup table,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup table{box-sizing:border-box;border-spacing:2px;border-collapse:separate;text-indent:0}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup th,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup th{padding:1px}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup th,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup th{font-weight:700}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup table>tr,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tbody,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tfoot,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup thead,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup table>tr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tbody,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tfoot,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup thead{vertical-align:middle}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup th,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup th,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tr{vertical-align:inherit}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup table,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup th,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup table,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup th{border-color:gray}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tbody,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tfoot,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup thead,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tbody,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tfoot,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup thead,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tr{border-color:inherit}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup button,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup input,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup keygen,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup optgroup,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup option,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup select,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup textarea,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup button,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup input,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup keygen,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup optgroup,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup option,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup select,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup textarea{text-indent:0}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup textarea,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup textarea{white-space:pre-wrap}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup button,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup input[type=button],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup input[type=checkbox],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup input[type=radio],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup input[type=reset],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup input[type=submit],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup select,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup button,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup input[type=button],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup input[type=checkbox],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup input[type=radio],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup input[type=reset],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup input[type=submit],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup select{box-sizing:border-box}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup button,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup input[type=button],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup button,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup input[type=button]{padding:.3em .5em}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup hr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup hr{color:gray;border-style:inset;border-width:1px;margin:.5em auto}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup fieldset,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup fieldset{margin-left:2px;margin-right:2px;border:2px groove ThreeDFace;padding:.35em .625em .75em}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup legend,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup legend{padding-left:2px;padding-right:2px}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup>:first-child,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup>:first-child{margin-top:0!important}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup>:last-child,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup>:last-child{margin-bottom:0!important}.layout-editor .img-responsive,.layout-editor .img-responsive img,.layout-editor .layout-content.layout-content-image>.layout-element-wrapper>.layout-content-markup>img,.layout-editor .layout-content.layout-content-vector-image>.layout-element-wrapper>.layout-content-markup>img,.layout-editor .layout-html.layout-content-image>.layout-element-wrapper>.layout-content-markup>img,.layout-editor .layout-html.layout-content-vector-image>.layout-element-wrapper>.layout-content-markup>img{display:block;width:100%;max-width:100%;height:auto}.layout-editor>.layout-toolbox-wrapper{position:relative;margin-left:12px;width:220px;-ms-flex-negative:0;flex-shrink:0}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox{border:1px solid #e4e5e6;width:220px;min-height:400px;padding:6px;background-color:#f3f4f5}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox.sticky-top{position:fixed;top:0;max-height:100%;overflow-y:auto}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox.sticky-bottom{position:absolute;bottom:0}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group{margin-top:12px}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group .layout-toolbox-group-heading{display:block;margin-bottom:4px;text-decoration:none}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group .layout-toolbox-group-heading:before{display:inline-block;width:10px;margin-right:4px;font:normal normal normal 14px/1 FontAwesome;text-align:center;content:"\f0d7"}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group.collapsed .layout-toolbox-group-heading:before{content:"\f0da"}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group.collapsed .layout-toolbox-items{display:none}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group .layout-toolbox-section+.layout-toolbox-section{margin-top:4px}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group .layout-toolbox-item{border:1px solid #e4e5e6;background-color:#fff;padding:9px 12px;cursor:default}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group .layout-toolbox-item i{display:inline-block;width:16px;font:normal normal normal 14px/1 FontAwesome}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group .layout-toolbox-item+.layout-toolbox-item{margin-top:4px}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group+.layout-toolbox-group{margin-top:6px}.layout-editor .layout-popup{display:none;position:absolute;margin:0;box-shadow:3px 3px 11px 0 rgba(50,50,50,.5);border:1px solid #e4e5e6;padding:2px 0;background-color:#f7f7f7;list-style:none;z-index:20;color:#7c7c7c;text-align:left;cursor:default;white-space:nowrap;line-height:normal;min-width:300px}.layout-editor .layout-popup.wide{width:600px}.layout-editor .layout-popup .layout-popup-flex{display:-ms-flexbox;display:flex;padding:2px 5px}.layout-editor .layout-popup .layout-popup-flex .layout-popup-column+.layout-popup-column{margin-left:4px;border-left:1px solid hsla(0,0%,50%,.15);padding-left:4px}.layout-editor .layout-popup .layout-popup-item{padding:4px 6px}.layout-editor .layout-popup .layout-popup-label{font-size:.9em;font-weight:700;color:#7c7c7c}.layout-editor .layout-popup .layout-popup-action:hover{background-color:#f3f4f5;cursor:pointer}.layout-editor .layout-popup .layout-popup-input input[type=text],.layout-editor .layout-popup .layout-popup-input textarea{width:100%}.layout-editor .layout-popup .layout-popup-input>label{display:block;font-size:.9em} +.layout-editor-toolbar{-ms-flex-pack:justify;justify-content:space-between;position:relative;top:10px}.layout-editor-toolbar,.layout-editor-toolbar .layout-editor-toolbar-group{display:-ms-flexbox;display:flex}.layout-editor-toolbar .layout-editor-toolbar-group>li+li{margin-left:12px}.layout-editor{display:-ms-flexbox;display:flex;margin-top:1em;font-size:14px}.layout-editor>.layout-canvas-wrapper{-ms-flex:1 1;flex:1 1;height:fit-content;background-color:#f3f4f5;border:1px solid #e4e5e6}.layout-editor>.layout-canvas-wrapper>.layout-toolbar-container{display:none;margin:12px 12px 0;min-height:71px}.layout-editor>.layout-canvas-wrapper>.layout-toolbar-container>.mce-panel{width:100%!important}.layout-editor>.layout-canvas-wrapper .layout-content>.layout-element-wrapper .layout-content-markup>.layout-placeholder{border:1px dashed #ccc;padding:.2em .4em;background:#e8e8e8}.layout-editor .layout-snippet{background:#e8e8e8}.layout-editor-help-dialog{display:none}.layout-editor-help-dialog .help-row:after,.layout-editor-help-dialog .help-row:before{content:" ";display:table}.layout-editor-help-dialog .help-row:after{clear:both}.layout-editor-help-dialog .help-row>.help-column-full,.layout-editor-help-dialog .help-row>.help-column-half{margin:.5em 0}.layout-editor-help-dialog .help-row>.help-column-half{box-sizing:border-box;float:left;width:50%}.layout-editor-help-dialog .help-row>.help-column-half:nth-child(2n){padding-right:10px;clear:left}.layout-editor-help-dialog .help-row+.help-row{margin-top:1em}.layout-editor-help-dialog code{border-radius:4px;background-color:#f3f4f5;padding:2px 4px;font-family:monospace}.layout-editor-help-dialog p{margin-bottom:.5em;line-height:1.6em}.layout-editor-help-dialog table>tbody>tr>td:first-child{padding-right:10px}.layout-editor .layout-element{position:relative;margin-top:0;margin-right:0;margin-bottom:0;padding:0}.layout-editor .layout-element:not(.layout-column){margin-left:0}.layout-editor .layout-element>.layout-element-wrapper>.layout-panel{display:none;position:absolute;margin:0;z-index:20;height:25px;padding:0 6px;list-style:none;white-space:nowrap;line-height:25px;vertical-align:middle}.layout-editor .layout-element>.layout-element-wrapper>.layout-panel>.layout-panel-item{display:inline-block;height:25px;padding:1px 6px 0}.layout-editor .layout-element>.layout-element-wrapper>.layout-panel>.layout-panel-label{font-size:13px}.layout-editor .layout-element>.layout-element-wrapper>.layout-panel>.layout-panel-action{display:none;width:28px;cursor:pointer;text-align:center}.layout-editor .layout-element>.layout-element-wrapper>.layout-panel-main{top:-27px;left:-2px}.layout-editor li.layout-element{list-style:none}.layout-editor:not(.layout-editor-dragging) .layout-element-active,.layout-editor:not(.layout-editor-dragging) .layout-element-focused{border-width:2px;border-style:solid}.layout-editor:not(.layout-editor-dragging) .layout-element-active>.layout-element-wrapper,.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper{margin:-2px}.layout-editor:not(.layout-editor-dragging) .layout-element-active{border-color:hsla(0,0%,41%,.1)}.layout-editor:not(.layout-editor-dragging) .layout-element-active>.layout-element-wrapper>.layout-panel-main{display:block;z-index:30;background-color:hsla(0,0%,41%,.1)}.layout-editor:not(.layout-editor-dragging) .layout-element-focused{border-color:#648721}.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper>.layout-panel{display:block;background-color:#648721;color:#fefefe}.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper>.layout-panel>.layout-panel-action{display:inline-block}.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper>.layout-panel>.layout-panel-action:hover{background-color:#82b02b}.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper>.layout-panel>.layout-panel-action.disabled{cursor:default;color:hsla(0,0%,100%,.4)}.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper>.layout-panel>.layout-panel-action.disabled:hover{background-color:#648721}.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper>.layout-panel>.layout-panel-action.active{color:#deff42;background-color:#739b26}.layout-editor:not(.layout-editor-dragging) .layout-element-focused>.layout-element-wrapper>.layout-panel>.layout-panel-action.active:hover{background-color:#82b02b}.layout-editor:not(.layout-editor-dragging) .layout-element-selected{background-color:rgba(100,135,33,.08)}.layout-editor .ui-sortable-placeholder{display:none}.layout-editor .layout-element-droptarget{box-shadow:inset 0 0 12px 6px rgba(100,135,33,.5)}.layout-editor .layout-element-droptarget .ui-sortable-placeholder{display:block;visibility:visible!important;min-height:78px;border:2px dashed #648721!important;background-color:rgba(100,135,33,.16)}.layout-editor .media-thumbnail img{max-width:100%;max-height:100%}.layout-editor .layout-container>.layout-element-wrapper>.layout-container-children-placeholder{display:none;-ms-flex-direction:column;flex-direction:column;margin:11px;min-height:80px;border:1px dashed hsla(0,0%,49%,.4);border-radius:4px;padding:12px;-ms-flex-pack:center;justify-content:center;font-size:13px;font-style:italic;opacity:.6;text-align:center}.layout-editor .layout-container>.layout-element-wrapper>.layout-children{padding:12px}.layout-editor .layout-container>.layout-element-wrapper>.layout-children>.layout-element:not(.layout-container)+.layout-element:not(.layout-container){margin-top:12px}.layout-editor .layout-container>.layout-element-wrapper>.layout-children>.ui-sortable-helper:first-child+.layout-element:not(.layout-container){margin-top:0}.layout-editor .layout-container>.layout-element-wrapper.layout-container-empty>.layout-container-children-placeholder{display:-ms-flexbox;display:flex}.layout-editor .layout-container>.layout-element-wrapper.layout-container-empty>.layout-children{position:absolute;top:0;right:0;bottom:0;left:0}.layout-editor:not(.layout-editor-dragging) .layout-container.layout-element-focused>.layout-element-wrapper>.layout-children>.layout-element:not(.layout-element-active){border:1px dashed hsla(0,0%,49%,.6)}.layout-editor:not(.layout-editor-dragging) .layout-container.layout-element-focused>.layout-element-wrapper>.layout-children>.layout-element:not(.layout-element-active)>.layout-element-wrapper{margin:-1px}.layout-editor:not(.layout-editor-dragging) .layout-container.layout-element-focused>.layout-element-wrapper>.layout-children>.layout-container+.layout-container:not(.layout-element-active){border-top:0}.layout-editor:not(.layout-editor-dragging) .layout-container.layout-element-focused>.layout-element-wrapper>.layout-children>.layout-container+.layout-container:not(.layout-element-active)>.layout-element-wrapper{margin-top:0}.layout-editor .layout-canvas #dummy{display:none}.layout-editor .layout-row.layout-element-focused:not(.layout-element-droptarget)>.layout-element-wrapper>.layout-children>.layout-element:not(.layout-element-active){border-top:1px dashed hsla(0,0%,49%,.6)!important}.layout-editor .layout-row.layout-element-focused:not(.layout-element-droptarget)>.layout-element-wrapper>.layout-children>.layout-element:not(.layout-element-active)>.layout-element-wrapper{margin-top:-1px!important}.layout-editor .layout-row.layout-element-focused:not(.layout-element-droptarget)>.layout-element-wrapper>.layout-children>.layout-element+.layout-element:not(.layout-element-active){border-left:0!important}.layout-editor .layout-row.layout-element-focused:not(.layout-element-droptarget)>.layout-element-wrapper>.layout-children>.layout-element+.layout-element:not(.layout-element-active)>.layout-element-wrapper{margin-left:0!important}.layout-editor .layout-column>.layout-element-wrapper>.layout-column-resize-bar{display:none;position:absolute;z-index:30;top:0;width:16px;height:100%;cursor:col-resize}.layout-editor .layout-column>.layout-element-wrapper>.layout-column-resize-bar-left{left:-6px}.layout-editor .layout-column>.layout-element-wrapper>.layout-column-resize-bar-right{right:-6px}.layout-editor .layout-column.layout-element-focused>.layout-element-wrapper>.layout-column-resize-bar{display:block}.layout-editor .layout-content,.layout-editor .layout-html{min-height:1em}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup{padding:2px;overflow-x:hidden;line-height:normal}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup *,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup *{margin:0;padding:0;box-sizing:content-box}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup address,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup blockquote,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup center,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup div,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup figcaption,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup figure,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup footer,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup form,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup header,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup hr,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup legend,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup listing,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup p,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup plaintext,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup pre,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup xmp,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup address,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup blockquote,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup center,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup div,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup figcaption,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup figure,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup footer,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup form,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup header,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup hr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup legend,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup listing,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup p,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup plaintext,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup pre,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup xmp{display:block}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup blockquote,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup figure,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup listing,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup p,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup plaintext,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup pre,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup xmp,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup blockquote,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup figure,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup listing,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup p,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup plaintext,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup pre,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup xmp{margin-top:1em;margin-bottom:1em}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup blockquote,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup figure,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup blockquote,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup figure{margin-left:40px;margin-right:40px}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup address,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup address{font-style:italic}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup listing,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup plaintext,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup pre,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup xmp,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup listing,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup plaintext,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup pre,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup xmp{font-family:monospace;white-space:pre}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup cite,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dfn,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup em,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup i,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup var,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup cite,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dfn,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup em,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup i,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup var{font-style:italic}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup b,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup strong,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup b,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup strong{font-weight:bolder}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup code,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup kbd,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup samp,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tt,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup code,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup kbd,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup samp,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tt{font-family:monospace}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup big,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup big{font-size:larger}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup small,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup small{font-size:smaller}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup sub,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup sub{vertical-align:sub}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup sup,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup sup{vertical-align:super}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup sub,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup sup,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup sub,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup sup{line-height:normal;font-size:smaller}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ruby,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ruby{display:ruby}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rb,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rb{display:ruby-base;white-space:nowrap}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rt,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rt{display:ruby-text;white-space:nowrap;font-size:50%;font-variant-east-asian:ruby;text-emphasis:none}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rbc,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rbc{display:ruby-base-container}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rtc,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rtc{display:ruby-text-container}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rb,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rbc,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rt,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup rtc,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ruby,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rb,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rbc,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rt,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup rtc,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ruby{unicode-bidi:isolate}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup :link,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup :link{color:#00e}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup :visited,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup :visited{color:#551a8b}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup :link,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup :visited,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup :link,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup :visited{text-decoration:underline}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup a:link[rel~=help],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup a:visited[rel~=help],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup area:link[rel~=help],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup area:visited[rel~=help],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup a:link[rel~=help],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup a:visited[rel~=help],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup area:link[rel~=help],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup area:visited[rel~=help]{cursor:help}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup :focus,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup :focus{outline:auto}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup mark,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup mark{background:#ff0;color:#000}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup abbr[title],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup acronym[title],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup abbr[title],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup acronym[title]{text-decoration:dotted underline}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ins,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup u,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ins,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup u{text-decoration:underline}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup del,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup s,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup strike,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup del,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup s,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup strike{text-decoration:line-through}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup blink,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup blink{text-decoration:blink}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup q:before,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup q:before{content:open-quote}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup q:after,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup q:after{content:close-quote}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup br:before,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup br:before{content:"\A";white-space:pre}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup nobr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup nobr{white-space:nowrap}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup wbr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup wbr{content:"\200B"}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup nobr wbr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup nobr wbr{white-space:normal}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup article,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup aside,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h1,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h2,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h3,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h4,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h5,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h6,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup hgroup,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup nav,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup section,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup article,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup aside,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h1,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h2,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h3,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h4,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h5,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h6,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup hgroup,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup nav,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup section{display:block}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h1,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h1{margin-top:.67em;margin-bottom:.67em;font-size:2em;font-weight:700}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h2,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h2{margin-top:.83em;margin-bottom:.83em;font-size:1.5em;font-weight:700}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h3,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h3{margin-top:1em;margin-bottom:1em;font-size:1.17em;font-weight:700}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h4,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h4{margin-top:1.33em;margin-bottom:1.33em;font-size:1em;font-weight:700}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h5,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h5{margin-top:1.67em;margin-bottom:1.67em;font-size:.83em;font-weight:700}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup h6,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup h6{margin-top:2.33em;margin-bottom:2.33em;font-size:.67em;font-weight:700}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dd,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dl,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dt,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dd,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dl,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dt,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul{display:block}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup li,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup li{display:list-item}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dl,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dl,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul{margin-top:1em;margin-bottom:1em}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir dl,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir ol,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dl dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dl dl,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dl ol,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dl ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol dl,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol ol,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul dl,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul ol,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir dl,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dl dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dl dl,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dl ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dl ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol dl,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul dl,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul ul{margin-top:0;margin-bottom:0}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dd,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dd{margin-left:40px}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul{padding-left:40px}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol{list-style-type:decimal}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul{list-style-type:disc}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul ul{list-style-type:circle}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir dir dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir dir ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir ol dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir ol ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir ul dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup dir ul ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol dir dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol dir ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol ol dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol ol ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol ul dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ol ul ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul dir dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul dir ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul ol dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul ol ul,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul ul dir,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup ul ul ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir dir dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir dir ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir ol dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir ol ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir ul dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup dir ul ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol dir dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol dir ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol ol dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol ol ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol ul dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ol ul ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul dir dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul dir ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul ol dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul ol ul,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul ul dir,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup ul ul ul{list-style-type:square}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup table,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup table{display:table}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup caption,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup caption{display:table-caption}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup colgroup,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup colgroup[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup colgroup,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup colgroup[hidden]{display:table-column-group}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup col,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup col[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup col,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup col[hidden]{display:table-column}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup thead,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup thead[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup thead,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup thead[hidden]{display:table-header-group}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tbody,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tbody[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tbody,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tbody[hidden]{display:table-row-group}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tfoot,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tfoot[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tfoot,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tfoot[hidden]{display:table-footer-group}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tr,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tr[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tr[hidden]{display:table-row}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup td[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup th,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup th[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup td[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup th,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup th[hidden]{display:table-cell}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup col[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup colgroup[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tbody[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup td[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tfoot[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup th[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup thead[hidden],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tr[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup col[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup colgroup[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tbody[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup td[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tfoot[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup th[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup thead[hidden],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tr[hidden]{visibility:collapse}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup table,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup table{box-sizing:border-box;border-spacing:2px;border-collapse:separate;text-indent:0}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup th,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup th{padding:1px}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup th,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup th{font-weight:700}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup table>tr,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tbody,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tfoot,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup thead,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup table>tr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tbody,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tfoot,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup thead{vertical-align:middle}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup th,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup th,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tr{vertical-align:inherit}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup table,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup th,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup table,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup td,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup th{border-color:gray}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tbody,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tfoot,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup thead,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup tr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tbody,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tfoot,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup thead,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup tr{border-color:inherit}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup button,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup input,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup keygen,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup optgroup,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup option,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup select,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup textarea,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup button,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup input,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup keygen,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup optgroup,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup option,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup select,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup textarea{text-indent:0}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup textarea,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup textarea{white-space:pre-wrap}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup button,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup input[type=button],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup input[type=checkbox],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup input[type=radio],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup input[type=reset],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup input[type=submit],.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup select,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup button,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup input[type=button],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup input[type=checkbox],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup input[type=radio],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup input[type=reset],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup input[type=submit],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup select{box-sizing:border-box}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup button,.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup input[type=button],.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup button,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup input[type=button]{padding:.3em .5em}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup hr,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup hr{color:gray;border-style:inset;border-width:1px;margin:.5em auto}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup fieldset,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup fieldset{margin-left:2px;margin-right:2px;border:2px groove ThreeDFace;padding:.35em .625em .75em}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup legend,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup legend{padding-left:2px;padding-right:2px}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup>:first-child,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup>:first-child{margin-top:0!important}.layout-editor .layout-content>.layout-element-wrapper .layout-content-markup>:last-child,.layout-editor .layout-html>.layout-element-wrapper .layout-content-markup>:last-child{margin-bottom:0!important}.layout-editor .img-responsive,.layout-editor .img-responsive img,.layout-editor .layout-content.layout-content-image>.layout-element-wrapper>.layout-content-markup>img,.layout-editor .layout-content.layout-content-vector-image>.layout-element-wrapper>.layout-content-markup>img,.layout-editor .layout-html.layout-content-image>.layout-element-wrapper>.layout-content-markup>img,.layout-editor .layout-html.layout-content-vector-image>.layout-element-wrapper>.layout-content-markup>img{display:block;width:100%;max-width:100%;height:auto}body .layout-toolbox-item{border:1px solid #e4e5e6;background-color:#fff;padding:9px 12px;cursor:default;list-style-type:none}body .layout-toolbox-item i{display:inline-block;width:16px;font:normal normal normal 14px/1 FontAwesome}body .layout-toolbox-item+.layout-toolbox-item{margin-top:4px}.layout-editor>.layout-toolbox-wrapper{position:sticky;top:1vh;padding-left:12px;width:220px;overflow-y:auto;scrollbar-width:thin;min-height:400px;max-height:98vh;height:100%}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox{border:1px solid #e4e5e6;padding:6px;background-color:#f3f4f5}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group .layout-toolbox-group-heading{display:block;margin-bottom:4px;text-decoration:none}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group .layout-toolbox-group-heading:before{display:inline-block;width:10px;margin-right:4px;font:normal normal normal 14px/1 FontAwesome;text-align:center;content:"\f0d7"}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group.collapsed .layout-toolbox-group-heading:before{content:"\f0da"}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group.collapsed .layout-toolbox-items{display:none}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group .layout-toolbox-section+.layout-toolbox-section{margin-top:4px}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group .layout-toolbox-item{border:1px solid #e4e5e6;background-color:#fff;padding:9px 12px;cursor:default}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group .layout-toolbox-item i{display:inline-block;width:16px;font:normal normal normal 14px/1 FontAwesome}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group .layout-toolbox-item+.layout-toolbox-item{margin-top:4px}.layout-editor>.layout-toolbox-wrapper>.layout-toolbox .layout-toolbox-group+.layout-toolbox-group{margin-top:6px}.layout-editor .layout-popup{display:none;position:absolute;margin:0;box-shadow:3px 3px 11px 0 rgba(50,50,50,.5);border:1px solid #e4e5e6;padding:2px 0;background-color:#f7f7f7;list-style:none;z-index:20;color:#7c7c7c;text-align:left;cursor:default;white-space:nowrap;line-height:normal;min-width:300px}.layout-editor .layout-popup.wide{width:600px}.layout-editor .layout-popup .layout-popup-flex{display:-ms-flexbox;display:flex;padding:2px 5px}.layout-editor .layout-popup .layout-popup-flex .layout-popup-column+.layout-popup-column{margin-left:4px;border-left:1px solid hsla(0,0%,50%,.15);padding-left:4px}.layout-editor .layout-popup .layout-popup-item{padding:4px 6px}.layout-editor .layout-popup .layout-popup-label{font-size:.9em;font-weight:700;color:#7c7c7c}.layout-editor .layout-popup .layout-popup-action:hover{background-color:#f3f4f5;cursor:pointer}.layout-editor .layout-popup .layout-popup-input input[type=text],.layout-editor .layout-popup .layout-popup-input textarea{width:100%}.layout-editor .layout-popup .layout-popup-input>label{display:block;font-size:.9em} diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Styles/dialog.css b/src/Orchard.Web/Modules/Orchard.Layouts/Styles/dialog.css index 0a42f60cc22..82f08d78997 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Styles/dialog.css +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Styles/dialog.css @@ -17,6 +17,7 @@ font-size: inherit; text-align: inherit; width: inherit; + height: inherit; } .dialog-wrapper .dialog { diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/ViewModels/HtmlEditorViewModel.cs b/src/Orchard.Web/Modules/Orchard.Layouts/ViewModels/HtmlEditorViewModel.cs index dc64dab098e..ab84b14652f 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/ViewModels/HtmlEditorViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/ViewModels/HtmlEditorViewModel.cs @@ -1,5 +1,8 @@ -namespace Orchard.Layouts.ViewModels { +using Orchard.ContentManagement; + +namespace Orchard.Layouts.ViewModels { public class HtmlEditorViewModel { public string Text { get; set; } + public ContentPart Part { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Views/BlueprintAdmin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Layouts/Views/BlueprintAdmin/Index.cshtml index e5ff8767784..0fd745edb86 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Views/BlueprintAdmin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Views/BlueprintAdmin/Index.cshtml @@ -32,9 +32,17 @@ @blueprint.ElementTypeName @blueprint.BaseElementTypeName - @Html.ActionLink(T("Edit").Text, "Edit", "BlueprintAdmin", new { id = blueprint.Id, area = "Orchard.Layouts" }, null) @T(" | ") - @Html.ActionLink(T("Properties").Text, "Properties", "BlueprintAdmin", new { id = blueprint.Id, area = "Orchard.Layouts" }, null) @T(" | ") - @Html.ActionLink(T("Remove").Text, "Delete", "BlueprintAdmin", new { id = blueprint.Id, area = "Orchard.Layouts" }, new { itemprop = "RemoveUrl UnsafeUrl" }) + } diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Html.cshtml b/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Html.cshtml index 1df31b7320c..32bbe1ee98f 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Html.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Html.cshtml @@ -1,5 +1,5 @@ @model Orchard.Layouts.ViewModels.HtmlEditorViewModel
        @Html.LabelFor(m => m.Text, T("HTML")) - @Display.Body_Editor(EditorFlavor: "html", Text: Model.Text, AutoFocus: true) + @Display.Body_Editor(EditorFlavor: "html", Text: Model.Text, AutoFocus: true, Part: Model.Part)
        \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Menu.cshtml b/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Menu.cshtml index 47c31b4c3d4..b7fc135ffeb 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Menu.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Menu.cshtml @@ -1,7 +1,9 @@ @model Orchard.Layouts.ViewModels.MenuEditorViewModel + @{ var menuOptions = Model.Menus.Select(x => new SelectListItem {Text = Html.ItemDisplayText(x).ToString(), Value = x.Id.ToString(), Selected = x.Id == Model.CurrentMenuId}); } +
        @Html.LabelFor(m => m.CurrentMenuId, T("For Menu")) @Html.DropDownListFor(m => m.CurrentMenuId, menuOptions) diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Snippet.Field.Text.cshtml b/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Snippet.Field.Text.cshtml index c67088c4b66..4daf39d1e2f 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Snippet.Field.Text.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/Elements.Snippet.Field.Text.cshtml @@ -1,10 +1,14 @@ @model Orchard.Layouts.ViewModels.SnippetFieldViewModel + @{ var field = Model; } +
        - @Html.Label(field.Descriptor.Name, field.Descriptor.DisplayName.ToString()) + @Html.Label(field.Descriptor.Name, field.Descriptor.DisplayName?.Text ?? field.Descriptor.Name) + @Html.TextBox(field.Descriptor.Name, field.Value, new { @class = "text large" }) + @if (field.Descriptor.Description != null) { @Html.Hint(field.Descriptor.Description) } diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/LayoutEditor.cshtml b/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/LayoutEditor.cshtml index 0edfd9ebdef..54e74bd8784 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/LayoutEditor.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Views/EditorTemplates/LayoutEditor.cshtml @@ -40,7 +40,6 @@ } }); - angular.bootstrap($(".layout-editor-holder")[0], ["LayoutEditor"]); $(function () { var editorConfig = JSON.parse(LayoutEditor.decode("@Html.Raw(Url.Encode(Model.ConfigurationData))")); @@ -59,6 +58,8 @@ e.preventDefault(); }); }); + + angular.bootstrap($(".layout-editor-holder")[0], ["LayoutEditor"]); }); diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Views/ElementEditor.cshtml b/src/Orchard.Web/Modules/Orchard.Layouts/Views/ElementEditor.cshtml index c53b4adfc89..985c978320b 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Views/ElementEditor.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Views/ElementEditor.cshtml @@ -16,15 +16,15 @@ @* Only render the editor shapes if the dialog is not closing. *@ @if (Model.Submitted != true) { @Html.ValidationSummary() -using (Html.BeginFormAntiForgeryPost(Url.Action("Update", "Element", new {session = Model.SessionKey, area = "Orchard.Layouts"}))) { - foreach (var tab in Model.Tabs) { - var id = String.Format("element-{0}", tab.ToLowerInvariant()); + using (Html.BeginFormAntiForgeryPost(Url.Action("Update", "Element", new {session = Model.SessionKey, area = "Orchard.Layouts"}))) { + foreach (var tab in Model.Tabs) { + var orderedEditorsInTab = Model.EditorResult.Editors + .Where(editor => ShapePosition.Parse((String)editor.Metadata.Position).Name == tab) + .OrderBy(editor => ShapePosition.Parse((String)editor.Metadata.Position).Position); + var id = String.Format("element-{0}", tab.ToLowerInvariant());
        - @foreach (var editor in Model.EditorResult.Editors) { - var position = ShapePosition.Parse((String) editor.Metadata.Position); - if (position.Name == tab) { - @Display(editor) - } + @foreach (var editor in orderedEditorsInTab) { + @Display(editor) }
        } @@ -58,7 +58,7 @@ else {
        @T(titleFormat, Model.DisplayText)
        \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Web.config b/src/Orchard.Web/Modules/Orchard.Layouts/Web.config index 670c23e8659..f3b89952240 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Web.config @@ -7,7 +7,7 @@ - + @@ -21,39 +21,78 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/packages.config b/src/Orchard.Web/Modules/Orchard.Layouts/packages.config index 22c39f3eb4e..03c87ed9abb 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Layouts/packages.config @@ -1,12 +1,12 @@  - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Lists/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Lists/Controllers/AdminController.cs index 8b4c6560203..c4d0acf982f 100644 --- a/src/Orchard.Web/Modules/Orchard.Lists/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Lists/Controllers/AdminController.cs @@ -9,7 +9,6 @@ using Orchard.Core.Containers.Models; using Orchard.Core.Containers.Services; using Orchard.Core.Containers.ViewModels; -using Orchard.Core.Contents; using Orchard.Core.Contents.ViewModels; using Orchard.Core.Title.Models; using Orchard.Data; @@ -39,7 +38,7 @@ public AdminController( IOrchardServices services, IContentDefinitionManager contentDefinitionManager, IShapeFactory shapeFactory, - IContainerService containerService, + IContainerService containerService, IListViewService listViewService, ITransactionManager transactionManager) { @@ -92,7 +91,7 @@ public ActionResult Index(Core.Contents.ViewModels.ListContentsViewModel model, var pager = new Pager(_services.WorkContext.CurrentSite, pagerParameters); var pagerShape = Shape.Pager(pager).TotalItemCount(query.Count()); var pageOfLists = query.Slice(pager.GetStartIndex(), pager.PageSize); - + var listsShape = Shape.List(); listsShape.AddRange(pageOfLists.Select(x => _contentManager.BuildDisplay(x, "SummaryAdmin")).ToList()); var viewModel = Shape.ViewModel() @@ -171,10 +170,10 @@ public ActionResult Create(string id) { if (containerTypes.Count > 1) { return RedirectToAction("SelectType"); } - return RedirectToAction("Create", new {id = containerTypes.First().Name}); + return RedirectToAction("Create", new { id = containerTypes.First().Name }); } - return RedirectToAction("Create", "Admin", new {area = "Contents", id, returnUrl = Url.Action("Index", "Admin", new { area = "Orchard.Lists" })}); + return RedirectToAction("Create", "Admin", new { area = "Contents", id, returnUrl = Url.Action("Index", "Admin", new { area = "Orchard.Lists" }) }); } public ActionResult SelectType() { @@ -312,11 +311,11 @@ public ActionResult Insert(int containerId, int itemId, PagerParameters pagerPar LocalizedString message; if (previousItemContainer == null) { - message = T("{0} was moved to {2}", itemMetadata.DisplayText, Url.RouteUrl(containerMetadata.AdminRouteValues), containerMetadata.DisplayText); + message = T("{0} was moved to {2}.", itemMetadata.DisplayText, Url.RouteUrl(containerMetadata.AdminRouteValues), containerMetadata.DisplayText); } else if (previousItemContainer.Id != containerId) { var previousItemContainerMetadata = _contentManager.GetItemMetadata(commonPart.Container); - message = T("{0} was moved from {4} to {2}", + message = T("{0} was moved from {4} to {2}.", itemMetadata.DisplayText, Url.RouteUrl(containerMetadata.AdminRouteValues), containerMetadata.DisplayText, @@ -374,7 +373,7 @@ public ActionResult ListOperation(int containerId, ListOperation operation, Sort break; } - return RedirectToAction("List", new {containerId, page = pagerParameters.Page, pageSize = pagerParameters.PageSize}); + return RedirectToAction("List", new { containerId, page = pagerParameters.Page, pageSize = pagerParameters.PageSize }); } [HttpPost, ActionName("List")] @@ -393,7 +392,7 @@ public ActionResult ChangeListView(int containerId, string listViewName, PagerPa /// Only publishes the content if it is already published. /// private void RePublish(IContent content) { - if(content.ContentItem.VersionRecord.Published) + if (content.ContentItem.VersionRecord.Published) _contentManager.Publish(content.ContentItem); } @@ -439,7 +438,7 @@ private bool BulkMoveToList(IEnumerable selectedIds, int? targetContainerId if (!_services.Authorizer.Authorize(Orchard.Core.Contents.Permissions.EditContent, item, T("Couldn't move selected content."))) { return false; } - + // Ensure the item can be in that container. if (itemContentTypes.Any() && itemContentTypes.All(x => x.Name != item.ContentItem.ContentType)) { _services.TransactionManager.Cancel(); diff --git a/src/Orchard.Web/Modules/Orchard.Lists/Module.txt b/src/Orchard.Web/Modules/Orchard.Lists/Module.txt index a0945488f3f..10c7cf5a324 100644 --- a/src/Orchard.Web/Modules/Orchard.Lists/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Lists/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Introduces a preconfigured container-enabled content type. FeatureDescription: A basic container-enabled content type. Dependencies: Contents, Containers, Navigation, Orchard.Autoroute, Orchard.ContentPicker diff --git a/src/Orchard.Web/Modules/Orchard.Lists/Orchard.Lists.csproj b/src/Orchard.Web/Modules/Orchard.Lists/Orchard.Lists.csproj index 221b1b6f972..2826072e4ab 100644 --- a/src/Orchard.Web/Modules/Orchard.Lists/Orchard.Lists.csproj +++ b/src/Orchard.Web/Modules/Orchard.Lists/Orchard.Lists.csproj @@ -12,8 +12,8 @@ Properties Orchard.Lists Orchard.Lists - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,9 @@ + + + true @@ -49,11 +52,14 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True + @@ -61,28 +67,22 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -127,12 +127,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) @@ -226,7 +226,7 @@ - + 10.0 @@ -252,7 +252,7 @@ --> - + @@ -266,10 +266,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Lists/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Lists/Properties/AssemblyInfo.cs index 8d58404454e..cc2ed950110 100644 --- a/src/Orchard.Web/Modules/Orchard.Lists/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Lists/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Lists/Routes.cs b/src/Orchard.Web/Modules/Orchard.Lists/Routes.cs index d9afc73e31e..f6109bd7bb1 100644 --- a/src/Orchard.Web/Modules/Orchard.Lists/Routes.cs +++ b/src/Orchard.Web/Modules/Orchard.Lists/Routes.cs @@ -6,13 +6,7 @@ namespace Orchard.Lists { public class Routes : IRouteProvider { public void GetRoutes(ICollection routes) { - foreach (RouteDescriptor routeDescriptor in GetRoutes()) { - routes.Add(routeDescriptor); - } - } - - public IEnumerable GetRoutes() { - return new[] { + var routeDescriptors = new[] { new RouteDescriptor { Priority = 5, Route = new Route( @@ -90,6 +84,10 @@ public IEnumerable GetRoutes() { new MvcRouteHandler()) }, }; + + foreach (var routeDescriptor in routeDescriptors) { + routes.Add(routeDescriptor); + } } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Lists/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Lists/Views/Admin/Index.cshtml index 72af8aa5a69..b4e9eab9b3c 100644 --- a/src/Orchard.Web/Modules/Orchard.Lists/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Lists/Views/Admin/Index.cshtml @@ -13,7 +13,7 @@ diff --git a/src/Orchard.Web/Modules/Orchard.Lists/Views/BreadcrumbItem.Last.cshtml b/src/Orchard.Web/Modules/Orchard.Lists/Views/BreadcrumbItem.Last.cshtml index 270b7c97e73..6ae5ec501d7 100644 --- a/src/Orchard.Web/Modules/Orchard.Lists/Views/BreadcrumbItem.Last.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Lists/Views/BreadcrumbItem.Last.cshtml @@ -1 +1 @@ -@T(Model.Text.ToString()) \ No newline at end of file +@T(Html.Encode(Model.Text.ToString())) \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Lists/Views/BreadcrumbItem.cshtml b/src/Orchard.Web/Modules/Orchard.Lists/Views/BreadcrumbItem.cshtml index dec55a226c3..c8fc05623ee 100644 --- a/src/Orchard.Web/Modules/Orchard.Lists/Views/BreadcrumbItem.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Lists/Views/BreadcrumbItem.cshtml @@ -1 +1 @@ -@T(Model.Text.ToString()) \ No newline at end of file +@T(Html.Encode(Model.Text.ToString())) \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Lists/Views/Content.SummaryAdminCondensed.cshtml b/src/Orchard.Web/Modules/Orchard.Lists/Views/Content.SummaryAdminCondensed.cshtml index ae77ddcda3f..987e7b73c8b 100644 --- a/src/Orchard.Web/Modules/Orchard.Lists/Views/Content.SummaryAdminCondensed.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Lists/Views/Content.SummaryAdminCondensed.cshtml @@ -3,26 +3,32 @@ @using Orchard.Utility.Extensions; @{ ContentItem contentItem = Model.ContentItem; - var returnUrl = ViewContext.RequestContext.HttpContext.Request.ToUrlString(); + var returnUrl = ViewContext.RequestContext.HttpContext.Request.RawUrl; }
        - +

        @Html.ItemAdminLink(contentItem)

        -
        @contentItem.TypeDefinition.DisplayName
        @if (Model.Header != null) { -
        @Display(Model.Header)
        +
        @Display(Model.Header)
        }
        @if (Model.Content != null) { -
        @Display(Model.Content)
        +
        @Display(Model.Content)
        }
        \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Lists/Views/Parts.Container.BulkActions.cshtml b/src/Orchard.Web/Modules/Orchard.Lists/Views/Parts.Container.BulkActions.cshtml index 694fcf38897..e2b3fc0281e 100644 --- a/src/Orchard.Web/Modules/Orchard.Lists/Views/Parts.Container.BulkActions.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Lists/Views/Parts.Container.BulkActions.cshtml @@ -11,7 +11,7 @@
        -
        - + +
        + +
        + +
        +
          -
        • +
        • -

          +

        +
        - +

        @T("SELECTION")

        - +
        • -
          +
          @@ -81,10 +101,11 @@
        -
        + - @using(Script.Foot()) { - + } - -@Display.FootScripts() + + @Display.FootScripts() \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary.WebSearch/Web.config b/src/Orchard.Web/Modules/Orchard.MediaLibrary.WebSearch/Web.config new file mode 100644 index 00000000000..7d2afd9d066 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary.WebSearch/Web.config @@ -0,0 +1,94 @@ + + + + +
        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary.WebSearch/packages.config b/src/Orchard.Web/Modules/Orchard.MediaLibrary.WebSearch/packages.config new file mode 100644 index 00000000000..1909aa2de5d --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary.WebSearch/packages.config @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/AdminMenu.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/AdminMenu.cs index 8d3d5f48d66..1e28ed3160c 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/AdminMenu.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/AdminMenu.cs @@ -15,7 +15,8 @@ public void GetNavigation(NavigationBuilder builder) { builder.AddImageSet("media-library") .Add(T("Media"), "6", menu => menu.Add(T("Media"), "0", item => item.Action("Index", "Admin", new { area = "Orchard.MediaLibrary" }) - .Permission(Permissions.ManageOwnMedia))); + .Permission(Permissions.ManageOwnMedia) + .Permission(Permissions.SelectMediaContent))); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs index 0d0fbaef41e..a3a0ceb27ec 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs @@ -1,9 +1,12 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Web.Mvc; using Orchard.ContentManagement; +using Orchard.ContentManagement.MetaData; using Orchard.Core.Title.Models; +using Orchard.FileSystems.Media; using Orchard.Localization; using Orchard.Logging; using Orchard.MediaLibrary.Models; @@ -12,9 +15,7 @@ using Orchard.Mvc; using Orchard.Themes; using Orchard.UI.Navigation; -using Orchard.ContentManagement.MetaData; using Orchard.Validation; -using System.Collections.Generic; namespace Orchard.MediaLibrary.Controllers { [ValidateInput(false)] @@ -22,15 +23,18 @@ public class AdminController : Controller { private readonly IMediaLibraryService _mediaLibraryService; private readonly INavigationManager _navigationManager; private readonly IContentDefinitionManager _contentDefinitionManager; + private readonly IStorageProvider _storageProvider; public AdminController( IOrchardServices services, IMediaLibraryService mediaLibraryService, INavigationManager navigationManager, - IContentDefinitionManager contentDefinitionManager) { + IContentDefinitionManager contentDefinitionManager, + IStorageProvider storageProvider) { _mediaLibraryService = mediaLibraryService; _navigationManager = navigationManager; _contentDefinitionManager = contentDefinitionManager; + _storageProvider = storageProvider; Services = services; T = NullLocalizer.Instance; @@ -42,12 +46,18 @@ public AdminController( public ILogger Logger { get; set; } public ActionResult Index(string folderPath = "", bool dialog = false) { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot view media"))) + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.SelectMediaContent, folderPath)) { + Services.Notifier.Add(UI.Notify.NotifyType.Error, T("Cannot select media")); return new HttpUnauthorizedResult(); + } + + var userMediaFolder = _mediaLibraryService.GetUserMediaFolder(); + if (Services.Authorizer.Authorize(Permissions.ManageOwnMedia) && !Services.Authorizer.Authorize(Permissions.ManageMediaContent)) + _storageProvider.TryCreateFolder(userMediaFolder.MediaPath); // If the user is trying to access a folder above his boundaries, redirect him to his home folder var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.SelectMediaContent, folderPath) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { return RedirectToAction("Index", new { folderPath = rootMediaFolder.MediaPath, dialog }); } @@ -80,8 +90,10 @@ public ActionResult Index(string folderPath = "", bool dialog = false) { } public ActionResult Import(string folderPath, int? replaceId = null) { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot import media"))) - return new HttpUnauthorizedResult(); + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.ImportMediaContent, folderPath)) { + Services.Notifier.Add(UI.Notify.NotifyType.Error, T("Cannot import media")); + return RedirectToAction("Index", new { folderPath = folderPath }); + } var mediaProviderMenu = _navigationManager.BuildMenu("mediaproviders"); var imageSets = _navigationManager.BuildImageSets("mediaproviders"); @@ -99,7 +111,7 @@ public ActionResult Import(string folderPath, int? replaceId = null) { return HttpNotFound(); // Check permission - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(replaceMedia.FolderPath)) { + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.ImportMediaContent, folderPath) && !_mediaLibraryService.CanManageMediaFolder(replaceMedia.FolderPath)) { return new HttpUnauthorizedResult(); } @@ -107,7 +119,7 @@ public ActionResult Import(string folderPath, int? replaceId = null) { viewModel.FolderPath = replaceMedia.FolderPath; } else { // Check permission - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.ImportMediaContent, folderPath) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { return new HttpUnauthorizedResult(); } } @@ -117,11 +129,19 @@ public ActionResult Import(string folderPath, int? replaceId = null) { [Themed(false)] public ActionResult MediaItems(string folderPath, int skip = 0, int count = 0, string order = "created", string mediaType = "") { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot view media"))) - return new HttpUnauthorizedResult(); + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.SelectMediaContent, folderPath)) { + Services.Notifier.Add(UI.Notify.NotifyType.Error, T("Cannot select media")); + var model = new MediaManagerMediaItemsViewModel { + MediaItems = new List(), + MediaItemsCount = 0, + FolderPath = folderPath + }; + + return View(model); + } // Check permission - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.SelectMediaContent, folderPath) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { var model = new MediaManagerMediaItemsViewModel { MediaItems = new List(), MediaItemsCount = 0, @@ -150,12 +170,18 @@ public ActionResult MediaItems(string folderPath, int skip = 0, int count = 0, s [Themed(false)] public ActionResult ChildFolders(string folderPath = null) { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot get child folder listing"))) - return new HttpUnauthorizedResult(); + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.SelectMediaContent, folderPath)) { + Services.Notifier.Add(UI.Notify.NotifyType.Error, T("Cannot get child folder listing")); + var model = new MediaManagerChildFoldersViewModel { + Children = new IMediaFolder[0] + }; + + return View(model); + } // Check permission var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + if (!_mediaLibraryService.CanManageMediaFolder(folderPath)) { var model = new MediaManagerChildFoldersViewModel { Children = new IMediaFolder[0] }; @@ -174,8 +200,10 @@ public ActionResult ChildFolders(string folderPath = null) { [Themed(false)] public ActionResult RecentMediaItems(int skip = 0, int count = 0, string order = "created", string mediaType = "") { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot view media"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) { + Services.Notifier.Add(UI.Notify.NotifyType.Error, T("Cannot view media")); return new HttpUnauthorizedResult(); + } var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); var rootMediaFolderPath = rootMediaFolder == null ? null : rootMediaFolder.MediaPath; @@ -203,9 +231,10 @@ public ActionResult MediaItem(int id, string displayType = "SummaryAdmin") { if (contentItem == null) return HttpNotFound(); - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, contentItem, T("Cannot view media")) - || !_mediaLibraryService.CanManageMediaFolder(contentItem.FolderPath)) + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.SelectMediaContent, contentItem.FolderPath)) { + Services.Notifier.Add(UI.Notify.NotifyType.Error, T("Cannot select media")); return new HttpUnauthorizedResult(); + } dynamic model = Services.ContentManager.BuildDisplay(contentItem, displayType); @@ -214,8 +243,10 @@ public ActionResult MediaItem(int id, string displayType = "SummaryAdmin") { [HttpPost] public ActionResult Delete(int[] mediaItemIds) { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't delete media items"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) { + Services.Notifier.Add(UI.Notify.NotifyType.Error, T("Couldn't delete media items")); return new HttpUnauthorizedResult(); + } var mediaItems = Services.ContentManager .Query(VersionOptions.Latest) @@ -226,9 +257,10 @@ public ActionResult Delete(int[] mediaItemIds) { try { foreach (var media in mediaItems) { - if (_mediaLibraryService.CanManageMediaFolder(media.FolderPath)) { - Services.ContentManager.Remove(media.ContentItem); + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.DeleteMediaContent, media.FolderPath)) { + return Json(false); } + Services.ContentManager.Remove(media.ContentItem); } return Json(true); @@ -241,18 +273,27 @@ public ActionResult Delete(int[] mediaItemIds) { [HttpPost] public ActionResult Clone(int mediaItemId) { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't clone media items"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) { + Services.Notifier.Add(UI.Notify.NotifyType.Error, T("Couldn't clone media items")); return new HttpUnauthorizedResult(); + } try { var media = Services.ContentManager.Get(mediaItemId).As(); - if (!_mediaLibraryService.CanManageMediaFolder(media.FolderPath)) { - return new HttpUnauthorizedResult(); + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.ImportMediaContent, media.FolderPath)) { + return Json(false); } var newFileName = _mediaLibraryService.GetUniqueFilename(media.FolderPath, media.FileName); + var settings = Services.WorkContext.CurrentSite.As(); + + // skip file if the allowed extensions is defined and doesn't match + if (!settings.IsFileAllowed(Path.GetFileName(newFileName))) { + return Json(false); + } + _mediaLibraryService.CopyFile(media.FolderPath, media.FileName, media.FolderPath, newFileName); var clonedContentItem = Services.ContentManager.Clone(media.ContentItem); diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/ClientStorageController.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/ClientStorageController.cs index b64e6dbadfb..fc61e3c6348 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/ClientStorageController.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/ClientStorageController.cs @@ -1,43 +1,50 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Web.Mvc; using Orchard.ContentManagement; +using Orchard.ContentManagement.Handlers; +using Orchard.FileSystems.Media; +using Orchard.Localization; +using Orchard.Logging; +using Orchard.MediaLibrary.Models; using Orchard.MediaLibrary.Services; using Orchard.MediaLibrary.ViewModels; using Orchard.Themes; using Orchard.UI.Admin; -using Orchard.MediaLibrary.Models; -using Orchard.Localization; -using System.Linq; -using Orchard.FileSystems.Media; namespace Orchard.MediaLibrary.Controllers { [Admin, Themed(false)] public class ClientStorageController : Controller { private readonly IMediaLibraryService _mediaLibraryService; private readonly IMimeTypeProvider _mimeTypeProvider; + private readonly IEnumerable _handlers; public ClientStorageController( IMediaLibraryService mediaManagerService, IOrchardServices orchardServices, - IMimeTypeProvider mimeTypeProvider) { + IMimeTypeProvider mimeTypeProvider, + IEnumerable handlers) { _mediaLibraryService = mediaManagerService; _mimeTypeProvider = mimeTypeProvider; + _handlers = handlers; Services = orchardServices; T = NullLocalizer.Instance; + Logger = NullLogger.Instance; } public IOrchardServices Services { get; set; } public Localizer T { get; set; } + public ILogger Logger { get; set; } public ActionResult Index(string folderPath, string type, int? replaceId = null) { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) { + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.SelectMediaContent, folderPath)) { return new HttpUnauthorizedResult(); } // Check permission - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + if (!_mediaLibraryService.CanManageMediaFolder(folderPath)) { return new HttpUnauthorizedResult(); } @@ -59,20 +66,17 @@ public ActionResult Index(string folderPath, string type, int? replaceId = null) [HttpPost] public ActionResult Upload(string folderPath, string type) { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) { + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.ImportMediaContent, folderPath)) { return new HttpUnauthorizedResult(); } // Check permission - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + if (!_mediaLibraryService.CanManageMediaFolder(folderPath)) { return new HttpUnauthorizedResult(); } var statuses = new List(); var settings = Services.WorkContext.CurrentSite.As(); - var allowedExtensions = (settings.UploadAllowedFileTypeWhitelist ?? "") - .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) - .Where(x => x.StartsWith(".")); // Loop through each file in the request for (int i = 0; i < HttpContext.Request.Files.Count; i++) { @@ -86,14 +90,12 @@ public ActionResult Upload(string folderPath, string type) { } // skip file if the allowed extensions is defined and doesn't match - if (allowedExtensions.Any()) { - if (!allowedExtensions.Any(e => filename.EndsWith(e, StringComparison.OrdinalIgnoreCase))) { - statuses.Add(new { - error = T("This file type is not allowed: {0}", Path.GetExtension(filename)).Text, - progress = 1.0, - }); - continue; - } + if (!settings.IsFileAllowed(filename)) { + statuses.Add(new { + error = T("This file is not allowed: {0}", filename).Text, + progress = 1.0, + }); + continue; } try { @@ -109,9 +111,16 @@ public ActionResult Upload(string folderPath, string type) { url = mediaPart.FileName, }); } + catch (InvalidNameCharacterException) { + statuses.Add(new { + error = T("The file name contains invalid character(s)").Text, + progress = 1.0, + }); + } catch (Exception ex) { + Logger.Error(ex, T("Unexpected exception when uploading a media.").Text); statuses.Add(new { - error = T(ex.Message).Text, + error = ex.Message, progress = 1.0, }); } @@ -131,16 +140,14 @@ public ActionResult Replace(int replaceId, string type) { return HttpNotFound(); // Check permission - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(replaceMedia.FolderPath)) { + if (!(_mediaLibraryService.CheckMediaFolderPermission(Permissions.EditMediaContent, replaceMedia.FolderPath) && _mediaLibraryService.CheckMediaFolderPermission(Permissions.ImportMediaContent, replaceMedia.FolderPath)) + && !_mediaLibraryService.CanManageMediaFolder(replaceMedia.FolderPath)) { return new HttpUnauthorizedResult(); } var statuses = new List(); var settings = Services.WorkContext.CurrentSite.As(); - var allowedExtensions = (settings.UploadAllowedFileTypeWhitelist ?? "") - .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) - .Where(x => x.StartsWith(".")); // Loop through each file in the request for (int i = 0; i < HttpContext.Request.Files.Count; i++) { @@ -149,19 +156,18 @@ public ActionResult Replace(int replaceId, string type) { var filename = Path.GetFileName(file.FileName); // if the file has been pasted, provide a default name - if (file.ContentType.Equals("image/png", StringComparison.InvariantCultureIgnoreCase) && !filename.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase)) { + if (file.ContentType.Equals("image/png", StringComparison.InvariantCultureIgnoreCase) + && !filename.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase)) { filename = "clipboard.png"; } // skip file if the allowed extensions is defined and doesn't match - if (allowedExtensions.Any()) { - if (!allowedExtensions.Any(e => filename.EndsWith(e, StringComparison.OrdinalIgnoreCase))) { - statuses.Add(new { - error = T("This file type is not allowed: {0}", Path.GetExtension(filename)).Text, - progress = 1.0, - }); - continue; - } + if (!settings.IsFileAllowed(filename)) { + statuses.Add(new { + error = T("This file is not allowed: {0}", filename).Text, + progress = 1.0, + }); + continue; } try { @@ -171,13 +177,37 @@ public ActionResult Replace(int replaceId, string type) { if (!replaceContentType.Equals(replaceMedia.TypeDefinition.Name, StringComparison.OrdinalIgnoreCase)) throw new Exception(T("Cannot replace {0} with {1}", replaceMedia.TypeDefinition.Name, replaceContentType).Text); - _mediaLibraryService.DeleteFile(replaceMedia.FolderPath, replaceMedia.FileName); + // Raise update and publish events which will update relevant Media properties + _handlers.Invoke(x => x.Updating(new UpdateContentContext(replaceMedia.ContentItem)), Logger); + + var mediaItemsUsingTheFile = Services.ContentManager.Query() + .ForVersion(VersionOptions.Latest) + .Where(x => x.FolderPath == replaceMedia.FolderPath && x.FileName == replaceMedia.FileName) + .Count(); + if (mediaItemsUsingTheFile == 1) { // if the file is referenced only by the deleted media content, the file too can be removed. + try { + _mediaLibraryService.DeleteFile(replaceMedia.FolderPath, replaceMedia.FileName); + } + catch (ArgumentException) { // File not found by FileSystemStorageProvider is thrown as ArgumentException. + statuses.Add(new { + error = T("Error when deleting file to replace: file {0} does not exist in folder {1}. Media has been updated anyway.", replaceMedia.FileName, replaceMedia.FolderPath).Text, + progress = 1.0 + }); + } + } + else { + // it changes the media file name + replaceMedia.FileName = filename; + } _mediaLibraryService.UploadMediaFile(replaceMedia.FolderPath, replaceMedia.FileName, file.InputStream); replaceMedia.MimeType = mimeType; - // Force a publish event which will update relevant Media properties - replaceMedia.ContentItem.VersionRecord.Published = false; - Services.ContentManager.Publish(replaceMedia.ContentItem); + _handlers.Invoke(x => x.Updated(new UpdateContentContext(replaceMedia.ContentItem)), Logger); + + var publishedVersion = replaceMedia.ContentItem.Record.Versions.SingleOrDefault(v => v.Published); + + _handlers.Invoke(x => x.Publishing(new PublishContentContext(replaceMedia.ContentItem, publishedVersion)), Logger); + _handlers.Invoke(x => x.Published(new PublishContentContext(replaceMedia.ContentItem, publishedVersion)), Logger); statuses.Add(new { id = replaceMedia.Id, @@ -189,6 +219,8 @@ public ActionResult Replace(int replaceId, string type) { }); } catch (Exception ex) { + Logger.Error(ex, T("Unexpected exception when uploading a media.").Text); + statuses.Add(new { error = T(ex.Message).Text, progress = 1.0, @@ -199,4 +231,4 @@ public ActionResult Replace(int replaceId, string type) { return Json(statuses, JsonRequestBehavior.AllowGet); } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/FolderController.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/FolderController.cs index 89d8fd9cae9..22036beb67d 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/FolderController.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/FolderController.cs @@ -2,6 +2,8 @@ using System.IO; using System.Linq; using System.Web.Mvc; +using Orchard.ContentManagement; +using Orchard.FileSystems.Media; using Orchard.Localization; using Orchard.Logging; using Orchard.MediaLibrary.Models; @@ -32,12 +34,14 @@ IMediaLibraryService mediaManagerService public Localizer T { get; set; } public ActionResult Create(string folderPath) { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't create media folder"))) - return new HttpUnauthorizedResult(); + if (!(_mediaLibraryService.CheckMediaFolderPermission(Permissions.ImportMediaContent, folderPath) || _mediaLibraryService.CheckMediaFolderPermission(Permissions.EditMediaContent, folderPath))) { + Services.Notifier.Error(T("Couldn't create media folder")); + return RedirectToAction("Index", "Admin", new { area = "Orchard.MediaLibrary", folderPath }); + } // If the user is trying to access a folder above his boundaries, redirect him to his home folder var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + if (!_mediaLibraryService.CanManageMediaFolder(folderPath)) { return RedirectToAction("Create", new { folderPath = rootMediaFolder.MediaPath }); } @@ -51,33 +55,46 @@ public ActionResult Create(string folderPath) { [HttpPost, ActionName("Create")] public ActionResult Create() { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't create media folder"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) { + Services.Notifier.Error(T("Couldn't create media folder")); return new HttpUnauthorizedResult(); + } var viewModel = new MediaManagerFolderCreateViewModel(); UpdateModel(viewModel); - if (!_mediaLibraryService.CanManageMediaFolder(viewModel.FolderPath)) { + if (!(_mediaLibraryService.CheckMediaFolderPermission(Permissions.ImportMediaContent, viewModel.FolderPath) + || _mediaLibraryService.CheckMediaFolderPermission(Permissions.EditMediaContent, viewModel.FolderPath))) { return new HttpUnauthorizedResult(); } + var failed = false; try { _mediaLibraryService.CreateFolder(viewModel.FolderPath, viewModel.Name); - Services.Notifier.Success(T("Media folder created")); + Services.Notifier.Information(T("Media folder created")); + } + catch (InvalidNameCharacterException) { + Services.Notifier.Error(T("The folder name contains invalid character(s).")); + failed = true; } catch (ArgumentException argumentException) { Services.Notifier.Error(T("Creating Folder failed: {0}", argumentException.Message)); + failed = true; + } + + if (failed) { Services.TransactionManager.Cancel(); return View(viewModel); } return RedirectToAction("Index", "Admin", new { area = "Orchard.MediaLibrary" }); - } public ActionResult Edit(string folderPath) { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't edit media folder"))) - return new HttpUnauthorizedResult(); + if (!(_mediaLibraryService.CheckMediaFolderPermission(Permissions.ImportMediaContent, folderPath) || _mediaLibraryService.CheckMediaFolderPermission(Permissions.EditMediaContent, folderPath))) { + Services.Notifier.Error(T("Couldn't edit media folder")); + return RedirectToAction("Index", "Admin", new { area = "Orchard.MediaLibrary", folderPath }); + } if (!_mediaLibraryService.CanManageMediaFolder(folderPath)) { return new HttpUnauthorizedResult(); @@ -88,6 +105,10 @@ public ActionResult Edit(string folderPath) { return new HttpUnauthorizedResult(); } + // Shouldn't be able to rename Users folder + if (folderPath == "Users") { + return new HttpUnauthorizedResult(); + } var viewModel = new MediaManagerFolderEditViewModel { FolderPath = folderPath, @@ -100,13 +121,16 @@ public ActionResult Edit(string folderPath) { [HttpPost, ActionName("Edit")] [FormValueRequired("submit.Save")] public ActionResult Edit() { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't edit media folder"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) { + Services.Notifier.Error(T("Couldn't edit media folder")); return new HttpUnauthorizedResult(); + } var viewModel = new MediaManagerFolderEditViewModel(); UpdateModel(viewModel); - if (!_mediaLibraryService.CanManageMediaFolder(viewModel.FolderPath)) { + if (!(_mediaLibraryService.CheckMediaFolderPermission(Permissions.ImportMediaContent, viewModel.FolderPath) + || _mediaLibraryService.CheckMediaFolderPermission(Permissions.EditMediaContent, viewModel.FolderPath))) { return new HttpUnauthorizedResult(); } @@ -117,7 +141,11 @@ public ActionResult Edit() { try { _mediaLibraryService.RenameFolder(viewModel.FolderPath, viewModel.Name); - Services.Notifier.Success(T("Media folder renamed")); + Services.Notifier.Information(T("Media folder renamed")); + } + catch (InvalidNameCharacterException) { + Services.Notifier.Error(T("The folder name contains invalid character(s).")); + return View(viewModel); } catch (Exception exception) { Services.Notifier.Error(T("Editing Folder failed: {0}", exception.Message)); @@ -130,16 +158,18 @@ public ActionResult Edit() { [HttpPost, ActionName("Edit")] [FormValueRequired("submit.Delete")] public ActionResult Delete() { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't delete media folder"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) { + Services.Notifier.Error(T("Couldn't delete media folder")); return new HttpUnauthorizedResult(); + } var viewModel = new MediaManagerFolderEditViewModel(); UpdateModel(viewModel); - if (!_mediaLibraryService.CanManageMediaFolder(viewModel.FolderPath)) { + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.DeleteMediaContent, viewModel.FolderPath)) { return new HttpUnauthorizedResult(); - } + try { _mediaLibraryService.DeleteFolder(viewModel.FolderPath); Services.Notifier.Success(T("Media folder deleted")); @@ -155,8 +185,11 @@ public ActionResult Delete() { [HttpPost] public ActionResult Move(string folderPath, int[] mediaItemIds) { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't move media items"))) + // check permission on destination folder + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.ImportMediaContent, folderPath)) { + Services.Notifier.Error(T("Couldn't move media items")); return new HttpUnauthorizedResult(); + } if (!_mediaLibraryService.CanManageMediaFolder(folderPath)) { return new HttpUnauthorizedResult(); @@ -166,7 +199,20 @@ public ActionResult Move(string folderPath, int[] mediaItemIds) { // don't try to rename the file if there is no associated media file if (!string.IsNullOrEmpty(media.FileName)) { + // check permission on source folder + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.DeleteMediaContent, media.FolderPath)) { + return new HttpUnauthorizedResult(); + } + + var settings = Services.WorkContext.CurrentSite.As(); + var uniqueFilename = _mediaLibraryService.GetUniqueFilename(folderPath, media.FileName); + + // skip file if the allowed extensions is defined and doesn't match + if (!settings.IsFileAllowed(Path.GetFileName(uniqueFilename))) { + continue; + } + _mediaLibraryService.MoveFile(media.FolderPath, media.FileName, folderPath, uniqueFilename); media.FileName = uniqueFilename; } diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/LocalizedMediaController.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/LocalizedMediaController.cs new file mode 100644 index 00000000000..9077d46eb08 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/LocalizedMediaController.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web.Mvc; +using Orchard.ContentManagement; +using Orchard.Core.Common.Models; +using Orchard.Core.Title.Models; +using Orchard.Environment.Extensions; +using Orchard.Indexing; +using Orchard.Localization; +using Orchard.Localization.Models; +using Orchard.Localization.Services; +using Orchard.Logging; +using Orchard.MediaLibrary.Models; +using Orchard.MediaLibrary.Services; +using Orchard.MediaLibrary.ViewModels; +using Orchard.Themes; +using Orchard.UI.Admin; + +namespace Orchard.MediaLibrary.Controllers { + [Admin] + [Themed(false)] + [OrchardFeature("Orchard.MediaLibrary.LocalizationExtensions")] + public class LocalizedMediaController : Controller { + private readonly IContentManager _contentManager; + private readonly IMediaLibraryService _mediaLibraryService; + private readonly ICultureManager _cultureManager; + + public LocalizedMediaController(IOrchardServices services, + IContentManager contentManager, + ICultureManager cultureManager, + IMediaLibraryService mediaLibraryService) { + _contentManager = contentManager; + _mediaLibraryService = mediaLibraryService; + _cultureManager = cultureManager; + Services = services; + + T = NullLocalizer.Instance; + Logger = NullLogger.Instance; + + } + public IOrchardServices Services { get; set; } + public Localizer T { get; set; } + public ILogger Logger { get; set; } + public ActionResult MediaItems(string folderPath, int skip = 0, int count = 0, string order = "created", string mediaType = "", string culture = "") { + if (String.IsNullOrWhiteSpace(folderPath)) { + folderPath = null; + } + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.SelectMediaContent, folderPath)) { + Services.Notifier.Add(UI.Notify.NotifyType.Error, T("Cannot select media")); + var model = new MediaManagerMediaItemsViewModel { + MediaItems = new List(), + MediaItemsCount = 0, + FolderPath = folderPath + }; + + return View(model); + } + + // Check permission + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.SelectMediaContent, folderPath) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + var model = new MediaManagerMediaItemsViewModel { + MediaItems = new List(), + MediaItemsCount = 0, + FolderPath = folderPath + }; + + return View(model); + } + + IEnumerable mediaParts; + var mediaPartsCount = 0; + if (culture == "") { + mediaParts = _mediaLibraryService.GetMediaContentItems(folderPath, skip, count, order, mediaType, VersionOptions.Latest); + mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(folderPath, mediaType, VersionOptions.Latest); + } + else { + var cultureId = _cultureManager.GetCultureByName(culture).Id; + var query = BuildGetMediaContentItemsQuery(Services.ContentManager, folderPath, order: order, mediaType: mediaType, versionOptions: VersionOptions.Latest) + .Join() + .Where(x => x.CultureId == cultureId) + .Join(); + mediaParts = query + .Slice(skip, count); + mediaPartsCount = query.Count(); + } + + var mediaItems = mediaParts.Select(x => new MediaManagerMediaItemViewModel { + MediaPart = x, + Shape = Services.ContentManager.BuildDisplay(x.ContentItem, "Thumbnail") + }).ToList(); + + var viewModel = new MediaManagerMediaItemsViewModel { + MediaItems = mediaItems, + MediaItemsCount = mediaPartsCount, + FolderPath = folderPath + }; + return View(viewModel); + } + + //TODO: extract the logic from MediaLibraryService and insert a method definition into IMediaLibraryService in order to give a point of extension + private static IContentQuery BuildGetMediaContentItemsQuery( + IContentManager contentManager, string folderPath = null, bool recursive = false, string order = null, string mediaType = null, VersionOptions versionOptions = null) { + + var query = contentManager.Query(versionOptions); + + query = query.Join(); + + if (!String.IsNullOrEmpty(mediaType)) { + query = query.ForType(new[] { mediaType }); + } + + if (!String.IsNullOrEmpty(folderPath)) { + if (recursive) { + query = query.Join().Where(m => m.FolderPath.StartsWith(folderPath)); + } + else { + query = query.Join().Where(m => m.FolderPath == folderPath); + } + } + + switch (order) { + case "title": + query = query.Join() + .OrderBy(x => x.Title) + .Join(); + break; + + case "modified": + query = query.Join() + .OrderByDescending(x => x.ModifiedUtc) + .Join(); + break; + + case "published": + query = query.Join() + .OrderByDescending(x => x.PublishedUtc) + .Join(); + break; + + default: + query = query.Join() + .OrderByDescending(x => x.CreatedUtc) + .Join(); + break; + } + + query = query.Join(); + + return query; + } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/OEmbedController.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/OEmbedController.cs index e1b1c3241b1..2d42832efcd 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/OEmbedController.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/OEmbedController.cs @@ -30,11 +30,11 @@ public OEmbedController( public Localizer T { get; set; } public ActionResult Index(string folderPath, string type, int? replaceId) { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.SelectMediaContent, folderPath)) return new HttpUnauthorizedResult(); // Check permission - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + if (!_mediaLibraryService.CanManageMediaFolder(folderPath)) { return new HttpUnauthorizedResult(); } @@ -147,12 +147,12 @@ public ActionResult IndexPOST(string folderPath, string url, string type, string [HttpPost, ValidateInput(false)] public ActionResult Import(string folderPath, string url, string document) { - if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) { + if (!_mediaLibraryService.CheckMediaFolderPermission(Permissions.ImportMediaContent, folderPath)) { return new HttpUnauthorizedResult(); } // Check permission - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + if (!_mediaLibraryService.CanManageMediaFolder(folderPath)) { return new HttpUnauthorizedResult(); } @@ -203,7 +203,8 @@ public ActionResult Replace(int replaceId, string url, string document) { return HttpNotFound(); // Check permission - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(replaceMedia.FolderPath)) { + if (!(_mediaLibraryService.CheckMediaFolderPermission(Permissions.EditMediaContent, replaceMedia.FolderPath) && _mediaLibraryService.CheckMediaFolderPermission(Permissions.ImportMediaContent, replaceMedia.FolderPath)) + && !_mediaLibraryService.CanManageMediaFolder(replaceMedia.FolderPath)) { return new HttpUnauthorizedResult(); } diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/AudioPartDriver.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/AudioPartDriver.cs index 0f56323e8fe..859db198be0 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/AudioPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/AudioPartDriver.cs @@ -1,4 +1,5 @@ using Orchard.ContentManagement.Drivers; +using Orchard.ContentManagement.Handlers; using Orchard.MediaLibrary.Models; namespace Orchard.MediaLibrary.Drivers { @@ -26,5 +27,8 @@ protected override void Importing(AudioPart part, ContentManagement.Handlers.Imp part.Length = int.Parse(length) ); } + protected override void Cloning(AudioPart originalPart, AudioPart clonePart, CloneContentContext context) { + clonePart.Length = originalPart.Length; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/DocumentPartDriver.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/DocumentPartDriver.cs index b70023a6740..0ef73494240 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/DocumentPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/DocumentPartDriver.cs @@ -1,4 +1,5 @@ using Orchard.ContentManagement.Drivers; +using Orchard.ContentManagement.Handlers; using Orchard.MediaLibrary.Models; namespace Orchard.MediaLibrary.Drivers { @@ -26,5 +27,8 @@ protected override void Importing(DocumentPart part, ContentManagement.Handlers. part.Length = int.Parse(length) ); } + protected override void Cloning(DocumentPart originalPart, DocumentPart clonePart, CloneContentContext context) { + clonePart.Length = originalPart.Length; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/ImagePartDriver.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/ImagePartDriver.cs index 57e8a400f0f..7fe045a73db 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/ImagePartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/ImagePartDriver.cs @@ -1,5 +1,6 @@ using Orchard.ContentManagement; using Orchard.ContentManagement.Drivers; +using Orchard.ContentManagement.Handlers; using Orchard.MediaLibrary.Models; namespace Orchard.MediaLibrary.Drivers { @@ -33,5 +34,10 @@ protected override void Importing(ImagePart part, ContentManagement.Handlers.Imp part.Width = int.Parse(width) ); } + + protected override void Cloning(ImagePart originalPart, ImagePart clonePart, CloneContentContext context) { + clonePart.Height = originalPart.Height; + clonePart.Width = originalPart.Width; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryExplorerLocalizationExtensionsPartDriver.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryExplorerLocalizationExtensionsPartDriver.cs new file mode 100644 index 00000000000..b518d4705da --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryExplorerLocalizationExtensionsPartDriver.cs @@ -0,0 +1,19 @@ +using Orchard.ContentManagement.Drivers; +using Orchard.Environment.Extensions; +using Orchard.Localization.Services; +using Orchard.MediaLibrary.Models; + +namespace Orchard.MediaLibrary.Drivers { + [OrchardFeature("Orchard.MediaLibrary.LocalizationExtensions")] + public class MediaLibraryExplorerLocalizationExtensionsPartDriver : ContentPartDriver { + private readonly ICultureManager _cultureManager; + public MediaLibraryExplorerLocalizationExtensionsPartDriver(ICultureManager cultureManager) { + _cultureManager = cultureManager; + + } + protected override DriverResult Display(MediaLibraryExplorerPart part, string displayType, dynamic shapeHelper) { + var cultures = _cultureManager.ListCultures(); + return ContentShape("Parts_MediaLibraryLocalization_Actions", () => shapeHelper.Parts_MediaLibraryLocalization_Actions(Cultures: cultures)); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryPickerFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryPickerFieldDriver.cs index 3c46ce5f4de..998ede7932c 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryPickerFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryPickerFieldDriver.cs @@ -45,7 +45,7 @@ protected override DriverResult Editor(ContentPart part, Fields.MediaLibraryPick ContentItems = _contentManager.GetMany(field.Ids, VersionOptions.Published, QueryHints.Empty).ToList(), }; - model.SelectedIds = string.Concat(",", field.Ids); + model.SelectedIds = string.Join(",", field.Ids); return shapeHelper.EditorTemplate(TemplateName: "Fields/MediaLibraryPicker.Edit", Model: model, Prefix: GetPrefix(field, part)); }); @@ -73,14 +73,20 @@ protected override DriverResult Editor(ContentPart part, Fields.MediaLibraryPick } protected override void Importing(ContentPart part, Fields.MediaLibraryPickerField field, ImportContentContext context) { - var contentItemIds = context.Attribute(field.FieldDefinition.Name + "." + field.Name, "ContentItems"); - if (contentItemIds != null) { - field.Ids = contentItemIds.Split(',') - .Select(context.GetItemFromSession) - .Select(contentItem => contentItem.Id).ToArray(); - } - else { - field.Ids = new int[0]; + // If nothing about the field is inside the context, field is not modified. + // For this reason, check if the current element is inside the ImportContentContext. + var element = context.Data.Element(field.FieldDefinition.Name + "." + field.Name); + if (element != null) { + var contentItemIds = context.Attribute(field.FieldDefinition.Name + "." + field.Name, "ContentItems"); + if (contentItemIds != null) { + if (!string.IsNullOrWhiteSpace(contentItemIds)) { + field.Ids = contentItemIds.Split(',') + .Select(context.GetItemFromSession) + .Select(contentItem => contentItem.Id).ToArray(); + } + } else { + field.Ids = new int[0]; + } } } diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaPartDriver.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaPartDriver.cs index 47ab58a6121..6aa91d1d9b0 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaPartDriver.cs @@ -1,11 +1,11 @@ using Orchard.ContentManagement; using Orchard.ContentManagement.Drivers; +using Orchard.ContentManagement.Handlers; using Orchard.Localization; using Orchard.MediaLibrary.Models; namespace Orchard.MediaLibrary.Drivers { public class MediaPartDriver : ContentPartDriver { - protected override string Prefix { get { return "MediaPart"; } } @@ -27,7 +27,7 @@ protected override DriverResult Display(MediaPart part, string displayType, dyna } protected override DriverResult Editor(MediaPart part, IUpdateModel updater, dynamic shapeHelper) { - updater.TryUpdateModel(part, Prefix, new[] {"Caption", "AlternateText"}, null); + updater.TryUpdateModel(part, Prefix, new[] { "Caption", "AlternateText" }, null); return Editor(part, shapeHelper); } @@ -74,5 +74,14 @@ protected override void Exporting(MediaPart part, ContentManagement.Handlers.Exp context.Element(part.PartDefinition.Name).SetAttributeValue("FileName", part.FileName); context.Element(part.PartDefinition.Name).SetAttributeValue("LogicalType", part.LogicalType); } + + protected override void Cloning(MediaPart originalPart, MediaPart clonePart, CloneContentContext context) { + clonePart.Caption = originalPart.Caption; + clonePart.FileName = originalPart.FileName; + clonePart.FolderPath = originalPart.FolderPath; + clonePart.LogicalType = originalPart.LogicalType; + clonePart.AlternateText = originalPart.AlternateText; + clonePart.MimeType = originalPart.MimeType; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/OEmbedPartDriver.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/OEmbedPartDriver.cs index 76f7d920e46..81da1f09b3d 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/OEmbedPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/OEmbedPartDriver.cs @@ -4,9 +4,10 @@ using Orchard.MediaLibrary.Models; using System.Xml; using System.Xml.Linq; +using Orchard.ContentManagement.Handlers; +using System.Collections; -namespace Orchard.MediaLibrary.Drivers -{ +namespace Orchard.MediaLibrary.Drivers { public class OEmbedPartDriver : ContentPartDriver { protected override DriverResult Display(OEmbedPart part, string displayType, dynamic shapeHelper) { return Combined( @@ -55,5 +56,26 @@ protected override void Importing(OEmbedPart part, ContentManagement.Handlers.Im partElement.Add(xmlElement.Elements()); } } + + protected override void Cloning(OEmbedPart originalPart, OEmbedPart clonePart, CloneContentContext context) { + var partName = XmlConvert.EncodeName(typeof(OEmbedPart).Name); + + var infosetOriginalPart = originalPart.As(); + var infosetClonePart = clonePart.As(); + if (infosetOriginalPart != null && infosetClonePart != null) { + // OEmbedPart is not versionable thats why using Infoset.Element instead of VersionInfoset.Element + var originalElement = infosetOriginalPart.Infoset.Element; + var partOriginalElement = originalElement.Element(partName); + var cloneElement = infosetClonePart.Infoset.Element; + var partCloneElement = cloneElement.Element(partName); + + if (partCloneElement != null) + partCloneElement.Remove(); + + partCloneElement = new XElement(partName); + cloneElement.Add(partCloneElement); + partCloneElement.Add(partOriginalElement.Elements()); + } + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/VectorImagePartDriver.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/VectorImagePartDriver.cs index 6163658e998..35a15abca2a 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/VectorImagePartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/VectorImagePartDriver.cs @@ -1,4 +1,5 @@ using Orchard.ContentManagement.Drivers; +using Orchard.ContentManagement.Handlers; using Orchard.MediaLibrary.Models; namespace Orchard.MediaLibrary.Drivers { @@ -12,5 +13,9 @@ protected override DriverResult Display(VectorImagePart part, string displayType ContentShape("Parts_VectorImage_SummaryAdmin", () => shapeHelper.Parts_VectorImage_SummaryAdmin()) ); } + + protected override void Cloning(VectorImagePart originalPart, VectorImagePart clonePart, CloneContentContext context) { + // nothing todo at the moment cause the part is only defined + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/VideoPartDriver.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/VideoPartDriver.cs index 0aa2923e1f7..2c21dd1ab98 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/VideoPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/VideoPartDriver.cs @@ -1,4 +1,5 @@ using Orchard.ContentManagement.Drivers; +using Orchard.ContentManagement.Handlers; using Orchard.MediaLibrary.Models; namespace Orchard.MediaLibrary.Drivers { @@ -26,5 +27,9 @@ protected override void Importing(VideoPart part, ContentManagement.Handlers.Imp part.Length = int.Parse(length) ); } + + protected override void Cloning(VideoPart originalPart, VideoPart clonePart, CloneContentContext context) { + clonePart.Length = originalPart.Length; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Extensions/ContentItemExtensions.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Extensions/ContentItemExtensions.cs new file mode 100644 index 00000000000..c46a4888e3e --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Extensions/ContentItemExtensions.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Orchard.MediaLibrary.Fields; +using Orchard.MediaLibrary.Models; + +namespace Orchard.ContentManagement +{ + public static class ContentItemExtensions + { + public static EagerlyLoadQueryResult LoadMediaLibraryPickerFields(this IList items, IContentManager contentManager, int maximumLevel = 0) where T : class, IContent { + var eagerlyLoadQueryResult = new EagerlyLoadQueryResult(items, contentManager); + return eagerlyLoadQueryResult.IncludeMediaLibraryPickerFields(); + } + + public static EagerlyLoadQueryResult IncludeMediaLibraryPickerFields(this IContentQuery query) where T : class, IContent { + var manager = query.ContentManager; + var eagerlyLoadQueryResult = new EagerlyLoadQueryResult(query.List(), manager); + return eagerlyLoadQueryResult.IncludeMediaLibraryPickerFields(); + } + + public static EagerlyLoadQueryResult IncludeMediaLibraryPickerFields(this EagerlyLoadQueryResult eagerlyLoadQueryResult) where T : class, IContent { + var containerIds = new HashSet(); + foreach (var part in eagerlyLoadQueryResult.Result) { + var mediaLibraryPickerFields = part.ContentItem.Parts.SelectMany(p => p.Fields.Where(f => f is MediaLibraryPickerField).Cast()); + var ids = mediaLibraryPickerFields.SelectMany(f => f.Ids); + foreach (var id in ids) { + if (!containerIds.Contains(id)) + containerIds.Add(id); + } + } + Dictionary containersDictionary = eagerlyLoadQueryResult.ContentManager.GetTooMany(containerIds, VersionOptions.Published, QueryHints.Empty).ToDictionary(c => c.ContentItem.Id); + foreach (var resultPart in eagerlyLoadQueryResult.Result) { + var mediaLibraryPickerFields = resultPart.ContentItem.Parts.SelectMany(p => p.Fields.Where(f => f is MediaLibraryPickerField).Cast()); + foreach (var mediaLibraryPickerField in mediaLibraryPickerFields) { + var preloadedMedias = new List(); + foreach (var mediaId in mediaLibraryPickerField.Ids) { + MediaPart preloadedMedia = null; + if (containersDictionary.TryGetValue(mediaId, out preloadedMedia)) + preloadedMedias.Add(preloadedMedia); + } + mediaLibraryPickerField.MediaParts = preloadedMedias; + } + } + return eagerlyLoadQueryResult; + } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Fields/MediaLibraryPickerField.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Fields/MediaLibraryPickerField.cs index fac620f9e2b..74bc1e21375 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Fields/MediaLibraryPickerField.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Fields/MediaLibraryPickerField.cs @@ -4,11 +4,12 @@ using Orchard.ContentManagement; using Orchard.ContentManagement.FieldStorage; using Orchard.MediaLibrary.Models; +using Orchard.ContentManagement.Utilities; namespace Orchard.MediaLibrary.Fields { public class MediaLibraryPickerField : ContentField { private static readonly char[] separator = {'{', '}', ','}; - internal Lazy> _contentItems; + internal LazyField> _contentItems = new LazyField>(); public int[] Ids { get { return DecodeIds(Storage.Get()); } @@ -17,8 +18,9 @@ public int[] Ids { public IEnumerable MediaParts { get { - return _contentItems != null ? _contentItems.Value : Enumerable.Empty(); + return _contentItems != null ? (_contentItems.Value ?? Enumerable.Empty()) : Enumerable.Empty(); } + set { _contentItems.Value = value; } } /// diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaItemHandler.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaItemHandler.cs new file mode 100644 index 00000000000..84c8e99ea89 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaItemHandler.cs @@ -0,0 +1,78 @@ +using Orchard.ContentManagement.MetaData; +using Orchard.ContentManagement.MetaData.Models; +using Orchard.ContentTypes.Events; +using Orchard.MediaLibrary.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Orchard.MediaLibrary.Handlers { + /// + /// Automatically adds MediaPart to the content type if a content part is attached that needs it. + /// + public class MediaItemHandler : IContentDefinitionEventHandler { + private readonly IContentDefinitionManager _contentDefinitionManager; + + public MediaItemHandler(IContentDefinitionManager contentDefinitionManager) { + _contentDefinitionManager = contentDefinitionManager; + } + + public void ContentFieldAttached(ContentFieldAttachedContext context) { + } + + public void ContentFieldDetached(ContentFieldDetachedContext context) { + } + + public void ContentPartAttached(ContentPartAttachedContext context) { + AlterMediaItem(_contentDefinitionManager.GetTypeDefinition(context.ContentTypeName)); + } + + public void ContentPartCreated(ContentPartCreatedContext context) { + } + + public void ContentPartDetached(ContentPartDetachedContext context) { + } + + public void ContentPartImported(ContentPartImportedContext context) { + } + + public void ContentPartImporting(ContentPartImportingContext context) { + } + + public void ContentPartRemoved(ContentPartRemovedContext context) { + } + + public void ContentTypeCreated(ContentTypeCreatedContext context) { + AlterMediaItem(context.ContentTypeDefinition); + } + + public void ContentTypeImported(ContentTypeImportedContext context) { + AlterMediaItem(context.ContentTypeDefinition); + } + + public void ContentTypeImporting(ContentTypeImportingContext context) { + } + + public void ContentTypeRemoved(ContentTypeRemovedContext context) { + } + + private void AlterMediaItem(ContentTypeDefinition contentTypeDefinition) { + var partNames = new string[]{ + typeof(ImagePart).Name, + typeof(VectorImagePart).Name, + typeof(VideoPart).Name, + typeof(AudioPart).Name, + typeof(DocumentPart).Name, + typeof(OEmbedPart).Name }; + if (contentTypeDefinition != null && + contentTypeDefinition.Parts.Any(contentTypePartDefinition => + partNames.Contains(contentTypePartDefinition.PartDefinition.Name))) { + _contentDefinitionManager.AlterTypeDefinition(contentTypeDefinition.Name, + cfg => cfg + .WithPart(typeof(MediaPart).Name) + .WithSetting("Stereotype", "Media")); + } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaLibraryPickerFieldHandler.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaLibraryPickerFieldHandler.cs index 8f29e137b89..8817eb5b48a 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaLibraryPickerFieldHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaLibraryPickerFieldHandler.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Linq; using Orchard.ContentManagement; using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.MetaData; @@ -9,16 +7,10 @@ namespace Orchard.MediaLibrary.Handlers { public class MediaLibraryPickerFieldHandler : ContentHandler { - private readonly IContentManager _contentManager; private readonly IContentDefinitionManager _contentDefinitionManager; - public MediaLibraryPickerFieldHandler( - IContentManager contentManager, - IContentDefinitionManager contentDefinitionManager) { - - _contentManager = contentManager; + public MediaLibraryPickerFieldHandler(IContentDefinitionManager contentDefinitionManager) { _contentDefinitionManager = contentDefinitionManager; - } protected override void Loaded(LoadContentContext context) { @@ -37,7 +29,9 @@ private void InitilizeLoader(ContentItem contentItem) { foreach (var field in fields) { var localField = field; - localField._contentItems = new Lazy>(() => _contentManager.GetMany(localField.Ids, VersionOptions.Published, QueryHints.Empty).ToList()); + // Using context content item's ContentManager instead of injected one to avoid lifetime scope exceptions in case of LazyFields. + localField._contentItems.Loader(() => + contentItem.ContentManager.GetMany(localField.Ids, VersionOptions.Published, QueryHints.Empty).ToList()); } } } diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaLibraryPickerFieldLocalizationExtensionHandler.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaLibraryPickerFieldLocalizationExtensionHandler.cs new file mode 100644 index 00000000000..ed73b9b4921 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaLibraryPickerFieldLocalizationExtensionHandler.cs @@ -0,0 +1,137 @@ +using System.Collections.Generic; +using System.Linq; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Handlers; +using Orchard.Environment.Extensions; +using Orchard.Localization; +using Orchard.Localization.Models; +using Orchard.Localization.Services; +using Orchard.MediaLibrary.Fields; +using Orchard.MediaLibrary.Models; +using Orchard.MediaLibrary.Settings; +using Orchard.UI.Notify; + +namespace Orchard.MediaLibrary.Handlers { + [OrchardFeature("Orchard.MediaLibrary.LocalizationExtensions")] + public class MediaLibraryPickerFieldLocalizationExtensionHandler : ContentHandler { + private readonly IContentManager _contentManager; + private readonly ILocalizationService _localizationServices; + private readonly IOrchardServices _orchardServices; + + public MediaLibraryPickerFieldLocalizationExtensionHandler( + IOrchardServices orchardServices, + IContentManager contentManager, + ILocalizationService localizationServices) { + _contentManager = contentManager; + _orchardServices = orchardServices; + _localizationServices = localizationServices; + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + protected override void UpdateEditorShape(UpdateEditorContext context) { + //Here we implement the logic based on the settings introduced in MediaLibraryPickerFieldLocalizationSettings + //These settings should only be active if the ContentItem that is being updated has a LocalizationPart + if (context.ContentItem.Parts.Any(part => part is LocalizationPart)) { + var lPart = (LocalizationPart)context.ContentItem.Parts.Single(part => part is LocalizationPart); + var fields = context.ContentItem.Parts.SelectMany(x => x.Fields.Where(f => f.FieldDefinition.Name == typeof(MediaLibraryPickerField).Name)).Cast(); + var contentCulture = context.ContentItem.As().Culture != null ? context.ContentItem.As().Culture.Culture : null; + foreach (var field in fields) { + var fieldSettings = field.PartFieldDefinition.Settings.GetModel(); + var settings = field.PartFieldDefinition.Settings.GetModel(); + + if (settings.TryToLocalizeMedia) { + //try to replace items in the field with their translation + var itemsInField = _contentManager.GetMany(field.Ids, VersionOptions.Latest, QueryHints.Empty); + var mediaIds = new List(); + + // Flag to check if media have been removed from the field. + // This happens when the field is set to remove items without localization and one or more media items cannot be localized. + // This flag is used to display a model error when the field is required and every media item has been removed from it. + var mediaRemoved = false; + + foreach (var item in itemsInField) { + // negatives id whoud be localized + var mediaItem = _contentManager.Get(item.Id, VersionOptions.Latest); + var mediaIsLocalizable = mediaItem.As() != null; + var mediaCulture = mediaIsLocalizable && mediaItem.As().Culture != null ? mediaItem.As().Culture.Culture : null; + if (mediaItem != null && mediaIsLocalizable) { + // The media is localizable + if (contentCulture == mediaCulture) { + // The content culture and the media culture match + mediaIds.Add(mediaItem.Id); + } + else { + if (mediaCulture == null) { + // The media has not a culture, so it takes the content culture + _localizationServices.SetContentCulture(mediaItem, contentCulture); + mediaIds.Add(mediaItem.Id); + _orchardServices.Notifier.Warning(T( + "{0}: the media item {1} was culture neutral and it has been localized", + field.DisplayName, + mediaItem.As().FileName)); + } + else { + // The media has a culture + var localizedMedia = _localizationServices.GetLocalizedContentItem(mediaItem, contentCulture); + if (localizedMedia != null) { + // The media has a translation, so the field will replace current media with the right localized one. + mediaIds.Add(localizedMedia.Id); + _orchardServices.Notifier.Warning(T( + "{0}: the media item {1} has been replaced by its localized version", + field.DisplayName, + mediaItem.As().FileName)); + } + else { + if (!settings.RemoveItemsWithoutLocalization) { + // The media supports translations but have not a localized version, so it will be cloned in the right language + var clonedMedia = _contentManager.Clone(mediaItem); + var mediaLocalizationPart = mediaItem.As(); + if (mediaLocalizationPart != null) { + _localizationServices.SetContentCulture(clonedMedia, contentCulture); + clonedMedia.As().MasterContentItem = mediaLocalizationPart.MasterContentItem == null ? mediaItem : mediaLocalizationPart.MasterContentItem; + } + _contentManager.Publish(clonedMedia); + mediaIds.Add(clonedMedia.Id); + _orchardServices.Notifier.Warning(T( + "{0}: a localized version of media item {1} has been created", + field.DisplayName, + mediaItem.As().FileName)); + } + else { + _orchardServices.Notifier.Warning(T( + "{0}: the media item {1} has been removed from the field because its culture differs from content's culture", + field.DisplayName, + mediaItem.As().FileName)); + mediaRemoved = true; + } + } + } + } + } + else if (mediaItem != null && !mediaIsLocalizable) { + if (!settings.RemoveItemsWithNoLocalizationPart) { + mediaIds.Add(mediaItem.Id); + } + else { + _orchardServices.Notifier.Warning(T( + "{0}: the media item {1} has been removed from the field because culture neutral", + field.DisplayName, + mediaItem.As().FileName)); + mediaRemoved = true; + } + } + } + + field.Ids = mediaIds.Distinct().ToArray(); + + if (field.Ids.Length == 0 && fieldSettings.Required && mediaRemoved) { + context.Updater.AddModelError("Id", T("The {0} field is required.", field.DisplayName)); + } + } + } + } + } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaPartHandler.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaPartHandler.cs index 0376feca329..6ee649d8a2a 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaPartHandler.cs @@ -1,29 +1,54 @@ using System; +using System.IO; +using System.Linq; +using Orchard.ContentManagement; using Orchard.ContentManagement.Handlers; +using Orchard.ContentManagement.MetaData; +using Orchard.Core.Title.Models; using Orchard.Data; -using Orchard.MediaLibrary.Services; -using Orchard.MediaLibrary.Models; -using System.IO; using Orchard.FileSystems.Media; -using Orchard.ContentManagement; +using Orchard.MediaLibrary.Models; +using Orchard.MediaLibrary.Services; namespace Orchard.MediaLibrary.Handlers { public class MediaPartHandler : ContentHandler { private readonly IMediaLibraryService _mediaLibraryService; private readonly IStorageProvider _storageProvider; + private readonly IContentDefinitionManager _contentDefinitionManager; + private readonly IContentManager _contentManager; public MediaPartHandler( IStorageProvider storageProvider, IMediaLibraryService mediaLibraryService, - IRepository repository) { + IRepository repository, + IContentDefinitionManager contentDefinitionManager, + IContentManager contentManager) { _storageProvider = storageProvider; _mediaLibraryService = mediaLibraryService; + _contentDefinitionManager = contentDefinitionManager; + _contentManager = contentManager; Filters.Add(StorageFilter.For(repository)); + Filters.Add(new ActivatingFilter(contentType => { + var typeDefinition = _contentDefinitionManager.GetTypeDefinition(contentType); + // To avoid NRE when the handler runs for ad-hoc content types, e.g. MediaLibraryExplorer. + return typeDefinition == null ? + false : + typeDefinition.Parts.Any(contentTypePartDefinition => + contentTypePartDefinition.PartDefinition.Name == typeof(MediaPart).Name); + })); + OnRemoving((context, part) => RemoveMedia(part)); OnLoaded((context, part) => { - if (!String.IsNullOrEmpty(part.FileName)) { + if (!string.IsNullOrEmpty(part.FileName)) { part._publicUrl.Loader(() => _mediaLibraryService.GetMediaPublicUrl(part.FolderPath, part.FileName)); + } else { + // Usually, OEmbedParts won't directly have a source file, but we may be interested + // in easily accessing their source Url. + var oePart = part.As(); + if (oePart != null) { + part._publicUrl.Loader(() => oePart.Source); + } } }); @@ -98,7 +123,13 @@ public MediaPartHandler( protected void RemoveMedia(MediaPart part) { if (!string.IsNullOrEmpty(part.FileName)) { - _mediaLibraryService.DeleteFile(part.FolderPath, part.FileName); + var mediaItemsUsingTheFile = _contentManager.Query() + .ForVersion(VersionOptions.Latest) + .Where(x => x.FolderPath == part.FolderPath && x.FileName == part.FileName) + .Count(); + if (mediaItemsUsingTheFile == 1) { // if the file is referenced only by the deleted media content, the file too can be removed. + _mediaLibraryService.DeleteFile(part.FolderPath, part.FileName); + } } } diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/MediaFileName/MediaFileNameDriver.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/MediaFileName/MediaFileNameDriver.cs index c42c18320c5..42353deeb9d 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/MediaFileName/MediaFileNameDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/MediaFileName/MediaFileNameDriver.cs @@ -1,14 +1,14 @@ using System; using Orchard.ContentManagement; using Orchard.ContentManagement.Drivers; +using Orchard.FileSystems.Media; using Orchard.Localization; using Orchard.MediaLibrary.Models; using Orchard.MediaLibrary.Services; using Orchard.Security; using Orchard.UI.Notify; -namespace Orchard.MediaLibrary.MediaFileName -{ +namespace Orchard.MediaLibrary.MediaFileName { public class MediaFileNameDriver : ContentPartDriver { private readonly IAuthenticationService _authenticationService; private readonly IAuthorizationService _authorizationService; @@ -39,7 +39,7 @@ protected override DriverResult Editor(MediaPart part, IUpdateModel updater, dyn "Parts_Media_Edit_FileName", () => { var currentUser = _authenticationService.GetAuthenticatedUser(); - if (!_authorizationService.TryCheckAccess(Permissions.ManageMediaContent, currentUser, part)) { + if (!_authorizationService.TryCheckAccess(Permissions.EditMediaContent, currentUser, part)) { return null; } @@ -58,14 +58,22 @@ protected override DriverResult Editor(MediaPart part, IUpdateModel updater, dyn var priorFileName = model.FileName; if (updater.TryUpdateModel(model, Prefix, null, null)) { if (model.FileName != null && !model.FileName.Equals(priorFileName, StringComparison.OrdinalIgnoreCase)) { + var fieldName = "MediaFileNameEditorSettings.FileName"; + try { _mediaLibraryService.RenameFile(part.FolderPath, priorFileName, model.FileName); part.FileName = model.FileName; - + _notifier.Add(NotifyType.Success, T("File '{0}' was renamed to '{1}'", priorFileName, model.FileName)); } - catch (Exception) { - updater.AddModelError("MediaFileNameEditorSettings.FileName", T("Unable to rename file")); + catch (OrchardException) { + updater.AddModelError(fieldName, T("Unable to rename file. Invalid Windows file path.")); + } + catch (InvalidNameCharacterException) { + updater.AddModelError(fieldName, T("The file name contains invalid character(s).")); + } + catch (Exception exception) { + updater.AddModelError(fieldName, T("Unable to rename file: {0}", exception.Message)); } } } diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/MediaLocalizationMigrations.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/MediaLocalizationMigrations.cs new file mode 100644 index 00000000000..f79a55e807c --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/MediaLocalizationMigrations.cs @@ -0,0 +1,22 @@ +using System.Linq; +using Orchard.ContentManagement.MetaData; +using Orchard.Core.Contents.Extensions; +using Orchard.Data.Migration; +using Orchard.Environment.Extensions; +using Orchard.Localization.Models; + +namespace Orchard.MediaLibrary { + + [OrchardFeature("Orchard.MediaLibrary.LocalizationExtensions")] + public class MediaLocalizationMigrations : DataMigrationImpl { + public int Create() { + var mediaContentTypes = ContentDefinitionManager.ListTypeDefinitions().Where(x => x.Settings.ContainsKey("Stereotype") && x.Settings["Stereotype"].Equals("Media", System.StringComparison.InvariantCultureIgnoreCase)); + // adds LocalizationPart to all "Media" stereotypes + foreach (var mediaCT in mediaContentTypes) { + ContentDefinitionManager.AlterTypeDefinition(mediaCT.Name, td => td + .WithPart("LocalizationPart")); + } + return 1; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaLibrarySettingsPart.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaLibrarySettingsPart.cs index e1bd5062422..4d549cec94a 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaLibrarySettingsPart.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaLibrarySettingsPart.cs @@ -1,4 +1,6 @@ -using Orchard.ContentManagement; +using System; +using System.Linq; +using Orchard.ContentManagement; namespace Orchard.MediaLibrary.Models { public class MediaLibrarySettingsPart : ContentPart { @@ -10,5 +12,32 @@ public string UploadAllowedFileTypeWhitelist { get { return this.Retrieve(x => x.UploadAllowedFileTypeWhitelist); } set { this.Store(x => x.UploadAllowedFileTypeWhitelist, value); } } + + public int LimitConcurrentUploads { + get { return this.Retrieve(x => x.LimitConcurrentUploads); } + set { this.Store(x => x.LimitConcurrentUploads, value); } + } + + public bool IsFileAllowed(string filename) { + + var allowedExtensions = (UploadAllowedFileTypeWhitelist ?? "") + .Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) + .Where(x => x.StartsWith(".")) + .ToArray(); + + // skip file if the allowed extensions is defined and doesn't match + if (allowedExtensions.Any()) { + if (!allowedExtensions.Any(e => filename.EndsWith(e, StringComparison.OrdinalIgnoreCase))) { + return false; + } + } + + // web.config files are always ignored, even if the white list includes it + if (String.Equals(filename, "web.config", StringComparison.OrdinalIgnoreCase)) { + return false; + } + + return true; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaPart.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaPart.cs index 38647a55cec..b8cef2b4ac6 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaPart.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaPart.cs @@ -1,8 +1,10 @@ using System; using Orchard.ContentManagement; using Orchard.ContentManagement.FieldStorage.InfosetStorage; +using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Utilities; using Orchard.Core.Title.Models; +using Orchard.MediaLibrary.Handlers; namespace Orchard.MediaLibrary.Models { public class MediaPart : ContentPart { @@ -11,6 +13,8 @@ public class MediaPart : ContentPart { /// /// Gets or sets the title of the media. + /// This adds an implicit dependency on which will be resolved by an + /// in the . /// public string Title { get { return ContentItem.As().Title; } @@ -63,7 +67,7 @@ public string FileName { /// Gets the public Url of the media if stored locally. /// public string MediaUrl { - get { return _publicUrl.Value; } + get { return _publicUrl.Value; } } /// diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/WebSearchSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/WebSearchSettingsPart.cs deleted file mode 100644 index f1a9fc060ec..00000000000 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/WebSearchSettingsPart.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Orchard.ContentManagement; -using Orchard.ContentManagement.FieldStorage.InfosetStorage; - -namespace Orchard.MediaLibrary.Models { - public class WebSearchSettingsPart : ContentPart { - - public string ApiKey { - get { return this.As().Get("ApiKey"); } - set { this.As().Set("ApiKey", value); } - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Module.txt b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Module.txt index fc93674f247..d4d692d8782 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Module.txt @@ -2,12 +2,17 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Provides enhanced Media management tools. Features: Orchard.MediaLibrary: Name: Media Library Description: Provides enhanced Media management tools. - Dependencies: Title, Orchard.MediaProcessing, Orchard.Tokens, Orchard.Resources + Dependencies: Title, Orchard.ContentTypes, Orchard.MediaProcessing, Orchard.Tokens, Orchard.Resources + Category: Media + Orchard.MediaLibrary.LocalizationExtensions: + Name: Media Library Localization Extensions + Description: Provides settings to enable advanced localization behaviours for Media Library and Media Library Picker Field. + Dependencies: Orchard.MediaLibrary, Orchard.Localization Category: Media diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj index d07548bfa31..515420a2c31 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj @@ -12,8 +12,8 @@ Properties Orchard.MediaLibrary Orchard.MediaLibrary - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -25,6 +25,9 @@ + + + true @@ -48,14 +51,15 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - - ..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True + + ..\..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll @@ -71,29 +75,23 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -107,7 +105,6 @@ - @@ -116,7 +113,6 @@ - @@ -124,11 +120,17 @@ + + + + + + @@ -142,12 +144,20 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) + + + {0E7646E8-FE8F-43C1-8799-D97860925EC4} + Orchard.ContentTypes + + + {FBC8B571-ED50-49D8-8D9D-64AB7454A0D6} + Orchard.Localization {6f759635-13d7-4e94-bcc9-80445d63f117} @@ -162,7 +172,6 @@ - @@ -180,14 +189,12 @@ - - @@ -197,7 +204,6 @@ - @@ -205,6 +211,8 @@ + + @@ -233,9 +241,6 @@ - - - @@ -355,9 +360,6 @@ - - - @@ -404,7 +406,29 @@ - + + + + + + + + + + + + + + + + + + + + + + + 10.0 @@ -433,7 +457,7 @@ --> - + @@ -447,10 +471,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Permissions.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Permissions.cs index c308153ec9b..a2f7a2e6bb4 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Permissions.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Permissions.cs @@ -5,13 +5,21 @@ namespace Orchard.MediaLibrary { public class Permissions : IPermissionProvider { public static readonly Permission ManageMediaContent = new Permission { Description = "Manage Media", Name = "ManageMediaContent" }; - public static readonly Permission ManageOwnMedia = new Permission { Description = "Manage Own Media", Name = "ManageOwnMedia", ImpliedBy = new[] { ManageMediaContent } }; + public static readonly Permission ImportMediaContent = new Permission { Description = "Import All Media", Name = "ImportMedia", ImpliedBy = new[] { ManageMediaContent } }; + public static readonly Permission EditMediaContent = new Permission { Description = "Edit All Media", Name = "EditMedia", ImpliedBy = new[] { ManageMediaContent } }; + public static readonly Permission DeleteMediaContent = new Permission { Description = "Delete All Media", Name = "DeleteMedia", ImpliedBy = new[] { ManageMediaContent } }; + public static readonly Permission SelectMediaContent = new Permission { Description = "Select All Media", Name = "SelectMedia", ImpliedBy = new[] { ManageMediaContent, ImportMediaContent, EditMediaContent, DeleteMediaContent } }; + public static readonly Permission ManageOwnMedia = new Permission { Description = "Manage Own Media", Name = "ManageOwnMedia", ImpliedBy = new[] { ManageMediaContent, SelectMediaContent, ImportMediaContent, EditMediaContent, DeleteMediaContent } }; public virtual Feature Feature { get; set; } public IEnumerable GetPermissions() { return new[] { ManageMediaContent, + ImportMediaContent, + EditMediaContent, + DeleteMediaContent, + SelectMediaContent, ManageOwnMedia, }; } diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Placement.info b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Placement.info index 74448a7a3c6..5e9bea14e4d 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Placement.info +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Placement.info @@ -132,4 +132,10 @@ Parts_MediaLibrary_Navigation="Navigation:5" /> + + + diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Properties/AssemblyInfo.cs index 69f64639a79..83e66a7c7fd 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Properties/AssemblyInfo.cs @@ -31,6 +31,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/ClientStorageMenu.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/ClientStorageMenu.cs index e648903acfa..9357083324c 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/ClientStorageMenu.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/ClientStorageMenu.cs @@ -15,7 +15,8 @@ public void GetNavigation(NavigationBuilder builder) { builder.AddImageSet("clientstorage") .Add(T("My Computer"), "5", menu => menu.Action("Index", "ClientStorage", new { area = "Orchard.MediaLibrary" }) - .Permission(Permissions.ManageOwnMedia)); + .Permission(Permissions.ManageOwnMedia) + .Permission(Permissions.ImportMediaContent)); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/OEmbedMenu.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/OEmbedMenu.cs index 8be665eaa63..495699673b8 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/OEmbedMenu.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/OEmbedMenu.cs @@ -15,7 +15,8 @@ public void GetNavigation(NavigationBuilder builder) { builder.AddImageSet("oembed") .Add(T("Media Url"), "10", menu => menu.Action("Index", "OEmbed", new { area = "Orchard.MediaLibrary" }) - .Permission(Permissions.ManageOwnMedia)); + .Permission(Permissions.ManageOwnMedia) + .Permission(Permissions.ImportMediaContent)); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library-picker.js b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library-picker.js index e29e39343bc..24c283622c0 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library-picker.js +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library-picker.js @@ -103,7 +103,7 @@ .replace(/\{title\}/g, selectedData[i].title) .replace(/\{editLink\}/g, selectedData[i].editLink); var content = $(tmpl); - element.find('.media-library-picker.items ul').append(content); + element.find('.media-library-picker.items ul.media-items').append(content); } refreshIds(); @@ -130,7 +130,7 @@ element.on("click",'.media-library-picker-remove', function(e) { e.preventDefault(); if (!confirm(removePrompt)) return false; - $(this).closest('li').remove(); + $(this).closest('.media-library-picker.items > ul > li').remove(); refreshIds(); showSaveMsg(); return false; diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js index fb1d5f3426e..370ee4afd63 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js @@ -1,15 +1,15 @@ -var enhanceViewModel = function(viewModel) { +var enhanceViewModel = function (viewModel) { // extension point for other modules to alter the view model }; -var baseViewModel = function() { +var baseViewModel = function () { }; $(function () { (function (settings) { - function attachFolderTitleDropEvent (elements) { + function attachFolderTitleDropEvent(elements) { elements.droppable({ accept: function () { var targetId = $(this).data('term-id'); @@ -47,7 +47,7 @@ $(function () { folderPath: folderPath, mediaItemIds: ids, __RequestVerificationToken: settings.antiForgeryToken - }, + } }).done(function (result) { if (result) { if (viewModel.displayed()) { @@ -67,7 +67,7 @@ $(function () { }); } }); - }; + } var listWidth = $('#media-library-main-list').width(); var listHeight = $('#media-library-main-list').height(); @@ -105,7 +105,7 @@ $(function () { self.selected = ko.observable(); self.status = ko.observable(''); self.summary = ko.observable(''); - self.cssClass = ko.computed(function() { + self.cssClass = ko.computed(function () { var css = ''; if (self.selected()) { css += ' selected'; @@ -118,12 +118,14 @@ $(function () { return css; }); - self.publicationStatus = ko.computed(function() { - return self.data.published ? "" : draftText; + self.publicationStatus = ko.computed(function () { + var pubStatus = self.data.published ? "" : draftText; + var localization = (self.data.localization != "" ? "(" + self.data.localization + ")" : ""); + return pubStatus + " " + localization; }); // operations - self.setData = function(value) { + self.setData = function (value) { self.data = value; }; } @@ -140,6 +142,11 @@ $(function () { self.focus = ko.observable(); self.results = ko.observableArray(); self.displayed = ko.observable(); + self.isEveryItemSelected = ko.computed({ + read: function () { + return self.selection().length === self.results().length; + } + }); self.mediaItemsCount = 0; self.orderMedia = ko.observableArray(['created']); self.mediaType = ko.observableArray([]); @@ -148,7 +155,7 @@ $(function () { self.mediaFoldersRequestCount = ko.observable(0); self.mediaFoldersPendingRequest = ko.computed({ read: function () { - return (self.mediaFoldersRequestCount() > 0); + return self.mediaFoldersRequestCount() > 0; }, write: function (value) { if (value === true) { @@ -162,7 +169,7 @@ $(function () { self.mediaPendingRequest = ko.observable(false); self.pendingRequest = ko.computed({ read: function () { - return (self.mediaFoldersPendingRequest() || self.mediaPendingRequest()); + return self.mediaFoldersPendingRequest() || self.mediaPendingRequest(); }, write: function (value) { self.mediaPendingRequest(value); @@ -171,7 +178,7 @@ $(function () { self.getMediaItems = function (count, append) { var folderPath = self.displayed() || ''; - + if (self.mediaPendingRequest()) { return; } @@ -187,18 +194,20 @@ $(function () { self.pendingRequest(true); var url = self.loadMediaItemsUrl(folderPath, self.results().length, count, self.orderMedia(), self.mediaType()); - console.log(url); - + $.ajax({ type: "GET", url: url, cache: false - }).done(function(data) { + }).done(function (data) { var mediaItems = data.mediaItems; var mediaItemsFolderPath = data.folderPath; - if (mediaItemsFolderPath !== self.displayed()) { - return; + // When searching on "Recent" folder self.displayed() is null and mediaItemsFolderPath is a empty string. + if (!(mediaItemsFolderPath == '' && self.displayed() == null)) { + if (mediaItemsFolderPath !== self.displayed()) { + return; + } } self.mediaItemsCount = data.mediaItemsCount; @@ -214,35 +223,60 @@ $(function () { } } } - }).fail(function(data) { + + self.updateSelectAllText(); + }).fail(function (data) { console.error(data); - }).always(function() { + }).always(function () { self.pendingRequest(false); }); }; - self.clearSelection = function() { + self.updateSelectAllText = function () { + var element = $("#select-all-button"); + + element.html(self.isEveryItemSelected() ? element.data("select-none-text") : element.data("select-all-text")); + }; + + self.updateAllSelection = function () { + if (self.isEveryItemSelected()) { + self.clearSelection(); + } + else { + self.selectAll(); + } + + self.updateSelectAllText(); + }; + + self.selectAll = function () { + self.results().forEach(function (item) { + viewModel.toggleSelect(item, true); + }); + }; + + self.clearSelection = function () { this.focus(null); // unselect previous elements - self.selection().forEach(function(item) { + self.selection().forEach(function (item) { item.selected(false); }); self.selection([]); }; - self.focus.subscribe(function(oldValue) { + self.focus.subscribe(function (oldValue) { if (oldValue) { oldValue.hasFocus(false); } }, this, "beforeChange"); - self.afterRenderMediaFolderTemplate = function(elements, model) { + self.afterRenderMediaFolderTemplate = function (elements, model) { var childTitles = $(elements).find(".media-library-folder-title"); attachFolderTitleDropEvent(childTitles); }; - self.focus.subscribe(function(newValue) { + self.focus.subscribe(function (newValue) { if (newValue) { newValue.hasFocus(true); @@ -255,21 +289,21 @@ $(function () { type: "GET", url: url, cache: false - }).done(function(data) { + }).done(function (data) { newValue.summary(data); }); } } }); - self.displayFolder = function(folderPath) { + self.displayFolder = function (folderPath) { self.results([]); self.displayed(folderPath); self.loadMediaItemsUrl = function (f, skip, count, order, mediaType) { return settings.mediaItemsActionUrl + '?folderPath=' + encodeURIComponent(f) + '&skip=' + skip + '&count=' + count + '&order=' + order + '&mediaType=' + mediaType; }; - + self.getMediaItems(pageCount); }; @@ -278,22 +312,22 @@ $(function () { self.displayFolder(folderPath); }; - self.selectRecent = function() { + self.selectRecent = function () { History.pushState({ action: 'selectRecent' }, '', '?recent'); self.loadMediaItemsUrl = function (folderPath, skip, count, order, mediaType) { return settings.recentMediaItemsActionUrl + '?skip=' + skip + '&count=' + count + '&order=' + order + '&mediaType=' + mediaType; }; - + self.results([]); self.displayed(null); self.getMediaItems(pageCount); }; - self.toggleSelect = function(searchResult, force) { + self.toggleSelect = function (searchResult, force) { var index = $.inArray(searchResult, self.selection()); if (index == -1 || force) { - self.selection.remove(function(item) { return item.data.id == searchResult.data.id; }); + self.selection.remove(function (item) { return item.data.id == searchResult.data.id; }); self.selection.push(searchResult); searchResult.selected(true); } else { @@ -304,7 +338,7 @@ $(function () { this.focus(searchResult); }; - self.select = function(searchResult) { + self.select = function (searchResult) { var index = $.inArray(searchResult, self.selection()); if (index == -1) { self.clearSelection(); @@ -315,14 +349,14 @@ $(function () { this.focus(searchResult); }; - self.scrolled = function(data, event) { + self.scrolled = function (data, event) { var elem = event.target; if (elem.scrollTop > (elem.scrollHeight - elem.offsetHeight - 300)) { self.getMediaItems(pageCount, true); } }; - self.importMedia = function() { + self.importMedia = function () { var url = settings.importActionUrl + '?folderPath=' + encodeURIComponent(self.displayed()); window.location = url; }; @@ -337,7 +371,8 @@ $(function () { viewModel.selection().forEach(function (item) { ids.push(item.data.id); }); var actionurl = url + '?folderPath=' + encodeURIComponent(folder) + "&replaceId=" + encodeURIComponent(ids[0]); window.location = actionurl; - } + }; + var selectFolderOrRecent = function () { if (self.displayed()) { self.selectFolder(self.displayed()); @@ -366,13 +401,13 @@ $(function () { self.isExpanded = ko.observable(false); - self.isSelected = ko.computed(function() { + self.isSelected = ko.computed(function () { return (self.mediaIndexViewModel.displayed() == self.folderPath()); }); self.fetchChildren = function (deepestChildPath) { self.childFoldersFetchStatus = 1; - + var getChildFolderListUrl = function (f) { return settings.childFolderListingActionUrl + '?folderPath=' + encodeURIComponent(f); }; @@ -383,7 +418,8 @@ $(function () { $.ajax({ type: "GET", url: url, - cache: false + cache: false, + dataType: 'json' }).done(function (data) { var newChildFolders = data.childFolders; @@ -447,7 +483,7 @@ $(function () { }); enhanceViewModel(viewModel); - + ko.applyBindings(viewModel); if (settings.hasFolderPath && settings.folderPath != settings.rootFolderPath) { @@ -475,7 +511,7 @@ $(function () { History.pushState({ action: 'selectRecent' }, '', '?recent'); } - window.onpopstate = function(event) { + window.onpopstate = function (event) { if (event && event.state && event.state.action == 'displayFolder') { viewModel.displayFolder(event.state.folder); } @@ -485,7 +521,7 @@ $(function () { } }; - $("#media-library-main-list").on("mousedown", "li", function(e) { + $("#media-library-main-list").on("mousedown", "li", function (e) { // only for left click if (e.which != 1) { return; @@ -497,46 +533,49 @@ $(function () { } else { viewModel.select(searchResult); } - }).on("contextmenu", "li", function() { + }).on("contextmenu", "li", function () { var searchResult = ko.dataFor(this); viewModel.toggleSelect(searchResult); return false; }); var pickAndClose = function () { - if (parent.$.colorbox) { - var selectedData = []; - for (var i = 0; i < viewModel.selection().length; i++) { - var selection = viewModel.selection()[i]; - selectedData.push(selection.data); - } - parent.$.colorbox.selectedData = selectedData; - parent.$.colorbox.close(); - }; - } + if (parent.$.colorbox) { + var selectedData = []; + for (var i = 0; i < viewModel.selection().length; i++) { + var selection = viewModel.selection()[i]; + selectedData.push(selection.data); + } + parent.$.colorbox.selectedData = selectedData; + parent.$.colorbox.close(); + } + }; $("#media-library-main-selection-select > .button-select").on('click', function () { - pickAndClose(); + pickAndClose(); + }); + + $("#select-all-button").on('click', function () { + viewModel.updateAllSelection(); }); $("#media-library-main-list").on('dblclick', function () { - pickAndClose(); + pickAndClose(); }); - $("#media-library-main-selection-select > .button-cancel").on('click', function() { + $("#media-library-main-selection-select > .button-cancel").on('click', function () { if (parent.$.colorbox) { parent.$.colorbox.selectedData = null; parent.$.colorbox.close(); } - ; }); - $("#media-library-main-list").on("mouseover", ".media-thumbnail", function() { + $("#media-library-main-list").on("mouseover", ".media-thumbnail", function () { if (!$(this).hasClass("ui-draggable")) { $(this).draggable({ revert: 'invalid', //containment: 'li', - helper: function(event) { + helper: function (event) { var clone = $(event.currentTarget).clone().removeAttr('id'); clone.removeClass('selected'); clone.addClass('dragged-selection'); @@ -551,7 +590,7 @@ $(function () { cursor: 'move', distance: 10, appendTo: 'body', - create: function() { + create: function () { // position the handler a little left to the center to let the number of selected items to appear $(this).draggable("option", "cursorAt", { left: $(this).width() / 2 - 20, top: $(this).height() / 2 }); } @@ -559,13 +598,13 @@ $(function () { } }); - $('#delete-selection-button').click(function() { + $('#delete-selection-button').click(function () { if (!confirm(settings.deleteConfirmationMessage)) { return false; } var ids = []; - viewModel.selection().forEach(function(item) { ids.push(item.data.id); }); + viewModel.selection().forEach(function (item) { ids.push(item.data.id); }); var url = settings.deleteActionUrl; $.ajax({ @@ -577,15 +616,16 @@ $(function () { mediaItemIds: ids, __RequestVerificationToken: settings.antiForgeryToken } - }).done(function(result) { + }).done(function (result) { if (result) { - viewModel.results.remove(function(item) { + viewModel.results.remove(function (item) { return ids.indexOf(item.data.id) != -1; }); viewModel.clearSelection(); } else { console.log('failed to delete media items'); + alert(settings.unauthorizedMessage); } return false; }); @@ -620,6 +660,7 @@ $(function () { viewModel.getMediaItems(viewModel.pageCount); } else { console.log('failed to clone media items'); + alert(settings.unauthorizedMessage); } return false; }); @@ -627,4 +668,4 @@ $(function () { }); })(window.mediaLibrarySettings); -}) +}); \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Security/MediaAuthorizationEventHandler.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Security/MediaAuthorizationEventHandler.cs index 14bb48916df..ba07735a060 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Security/MediaAuthorizationEventHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Security/MediaAuthorizationEventHandler.cs @@ -21,14 +21,7 @@ public void Complete(CheckAccessContext context) { } public void Adjust(CheckAccessContext context) { var mediaPart = context.Content.As(); if (mediaPart != null) { - if(_authorizer.Authorize(Permissions.ManageMediaContent)) { - context.Granted = true; - return; - } - - if(_authorizer.Authorize(Permissions.ManageOwnMedia)) { - context.Granted = _mediaLibraryService.CanManageMediaFolder(mediaPart.FolderPath); - } + context.Granted = _mediaLibraryService.CheckMediaFolderPermission(context.Permission, mediaPart.FolderPath); } } } diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/IMediaLibraryService.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/IMediaLibraryService.cs index 092876cf648..232192f4900 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/IMediaLibraryService.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/IMediaLibraryService.cs @@ -22,7 +22,7 @@ public interface IMediaLibraryService : IDependency { MediaPart ImportMedia(Stream stream, string relativePath, string filename); MediaPart ImportMedia(Stream stream, string relativePath, string filename, string contentType); IMediaFactory GetMediaFactory(Stream stream, string mimeType, string contentType); - + bool CheckMediaFolderPermission(Orchard.Security.Permissions.Permission permission, string folderPath); /// /// Creates a unique filename to prevent filename collisions. /// @@ -41,6 +41,8 @@ public interface IMediaLibraryService : IDependency { IMediaFolder GetRootMediaFolder(); + IMediaFolder GetUserMediaFolder(); + /// /// Retrieves the media folders within a given relative path. /// @@ -143,7 +145,7 @@ public interface IMediaLibraryService : IDependency { string Combine(string path1, string path2); } - public static class MediaLibrayServiceExtensions { + public static class MediaLibraryServiceExtensions { public static bool CanManageMediaFolder(this IMediaLibraryService service, string folderPath) { // The current user can manage a media if he has access to the whole hierarchy // or the media is under his personal storage folder. diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/MediaLibraryService.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/MediaLibraryService.cs index af39b97fde4..e5b3bf7c1c1 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/MediaLibraryService.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/MediaLibraryService.cs @@ -6,13 +6,13 @@ using Orchard.ContentManagement; using Orchard.ContentManagement.MetaData.Models; using Orchard.Core.Common.Models; +using Orchard.Core.Title.Models; using Orchard.FileSystems.Media; using Orchard.Localization; using Orchard.MediaLibrary.Factories; using Orchard.MediaLibrary.Models; -using Orchard.Core.Title.Models; -using Orchard.Validation; using Orchard.MediaLibrary.Providers; +using Orchard.Validation; namespace Orchard.MediaLibrary.Services { public class MediaLibraryService : IMediaLibraryService { @@ -21,7 +21,6 @@ public class MediaLibraryService : IMediaLibraryService { private readonly IStorageProvider _storageProvider; private readonly IEnumerable _mediaFactorySelectors; private readonly IMediaFolderProvider _mediaFolderProvider; - private static char[] HttpUnallowed = new char[] { '<', '>', '*', '%', '&', ':', '\\', '?', '#' }; public MediaLibraryService( IOrchardServices orchardServices, @@ -80,7 +79,8 @@ public int GetMediaContentItemsCountRecursive(string folderPath, string mediaTyp return BuildGetMediaContentItemsQuery(_orchardServices.ContentManager, folderPath, true, mediaType: mediaType, versionOptions: versionOptions) .Count(); } - + + //TODO: extract the logic from MediaLibraryService and add a method definition into IMediaLibraryService in order to give a point of extension private static IContentQuery BuildGetMediaContentItemsQuery( IContentManager contentManager, string folderPath = null, bool recursive = false, string order = null, string mediaType = null, VersionOptions versionOptions = null) { @@ -94,7 +94,8 @@ private static IContentQuery BuildGetMediaContentItemsQuery( if (!String.IsNullOrEmpty(folderPath)) { if (recursive) { - query = query.Join().Where(m => m.FolderPath.StartsWith(folderPath)); + var subfolderSearch = folderPath.EndsWith(Path.DirectorySeparatorChar.ToString()) ? folderPath : folderPath + Path.DirectorySeparatorChar; + query = query.Join().Where(m => (m.FolderPath == folderPath || m.FolderPath.StartsWith(subfolderSearch))); } else { query = query.Join().Where(m => m.FolderPath == folderPath); @@ -144,12 +145,6 @@ public MediaPart ImportMedia(Stream stream, string relativePath, string filename } public string GetUniqueFilename(string folderPath, string filename) { - - // remove any char which is unallowed in an HTTP request - foreach (var unallowedChar in HttpUnallowed) { - filename = filename.Replace(unallowedChar.ToString(), ""); - } - // compute a unique filename var uniqueFilename = filename; var index = 1; @@ -176,9 +171,9 @@ public MediaPart ImportMedia(string relativePath, string filename, string conten var mediaFile = BuildMediaFile(relativePath, storageFile); using (var stream = storageFile.OpenRead()) { - var mediaFactory = GetMediaFactory(stream, mimeType, contentType); - if (mediaFactory == null) - throw new Exception(T("No media factory available to handle this resource.").Text); + var mediaFactory = GetMediaFactory(stream, mimeType, contentType) + ?? throw new Exception(T("No media factory available to handle this resource.").Text); + var mediaPart = mediaFactory.CreateMedia(stream, mediaFile.Name, mimeType, contentType); if (mediaPart != null) { mediaPart.FolderPath = relativePath; @@ -226,7 +221,7 @@ public string GetMediaPublicUrl(string mediaPath, string fileName) { } public IMediaFolder GetRootMediaFolder() { - if (_orchardServices.Authorizer.Authorize(Permissions.ManageMediaContent)) { + if (_orchardServices.Authorizer.Authorize(Permissions.SelectMediaContent)) { return null; } @@ -242,6 +237,39 @@ public IMediaFolder GetRootMediaFolder() { return null; } + public IMediaFolder GetUserMediaFolder() { + var currentUser = _orchardServices.WorkContext.CurrentUser; + var userPath = _storageProvider.Combine("Users", _mediaFolderProvider.GetFolderName(currentUser)); + return new MediaFolder() { + Name = currentUser.UserName, + MediaPath = userPath + }; + } + + public bool CheckMediaFolderPermission(Orchard.Security.Permissions.Permission permission, string folderPath) { + if (_orchardServices.Authorizer.Authorize(Permissions.ManageMediaContent)) { + return true; + } + if (_orchardServices.WorkContext.CurrentUser == null) + return _orchardServices.Authorizer.Authorize(permission); + // determines the folder type: public, user own folder (my), folder of another user (private) + var rootedFolderPath = this.GetRootedFolderPath(folderPath) ?? ""; + var userFolderPath = GetUserMediaFolder().MediaPath; + bool isMyfolder = false; + + if (rootedFolderPath.StartsWith(userFolderPath)) { + // the folder is the user's private path or one of its subfolders + isMyfolder = true; + } + + if (isMyfolder) { + return _orchardServices.Authorizer.Authorize(Permissions.ManageOwnMedia); + } + else { // other + return _orchardServices.Authorizer.Authorize(permission); + } + } + /// /// Retrieves the media folders within a given relative path. /// @@ -328,15 +356,16 @@ public void RenameFolder(string folderPath, string newFolderName) { Argument.ThrowIfNullOrEmpty(newFolderName, "newFolderName"); try { - var segments = folderPath.Split(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries).ToArray(); - var newFolderPath = String.Join(Path.DirectorySeparatorChar.ToString(), segments.Take(segments.Length - 1).Union(new[] { newFolderName })); + var parentIndex = folderPath.LastIndexOfAny(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); + var parentPath = parentIndex > 0 ? folderPath.Substring(0, parentIndex) : String.Empty; + var newFolderPath = _storageProvider.Combine(parentPath, newFolderName); var mediaParts = BuildGetMediaContentItemsQuery(_orchardServices.ContentManager, folderPath, true).List(); foreach (var mediaPart in mediaParts) { mediaPart.FolderPath = newFolderPath + mediaPart.FolderPath.Substring(folderPath.Length); } - _storageProvider.RenameFolder(folderPath, _storageProvider.Combine(Path.GetDirectoryName(folderPath), newFolderName)); + _storageProvider.RenameFolder(folderPath, newFolderPath); } catch (Exception) { _orchardServices.TransactionManager.Cancel(); diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/XmlRpcHandler.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/XmlRpcHandler.cs index 14a35ab0013..9a344801286 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/XmlRpcHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/XmlRpcHandler.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Web.Mvc; using System.Web.Routing; @@ -7,12 +8,14 @@ using Orchard.Core.XmlRpc; using Orchard.Core.XmlRpc.Models; using Orchard.Localization; +using Orchard.MediaLibrary.Models; using Orchard.Mvc.Extensions; using Orchard.Security; namespace Orchard.MediaLibrary.Services { public class XmlRpcHandler : IXmlRpcHandler { private readonly IContentManager _contentManager; + private readonly IOrchardServices _orchardServices; private readonly IMembershipService _membershipService; private readonly IAuthorizationService _authorizationService; private readonly IMediaLibraryService _mediaLibraryService; @@ -23,13 +26,14 @@ public XmlRpcHandler( IAuthorizationService authorizationService, IMediaLibraryService mediaLibraryService, RouteCollection routeCollection, - IContentManager contentManager) { + IContentManager contentManager, + IOrchardServices orchardServices) { _membershipService = membershipService; _authorizationService = authorizationService; _mediaLibraryService = mediaLibraryService; _routeCollection = routeCollection; _contentManager = contentManager; - + _orchardServices = orchardServices; T = NullLocalizer.Instance; } @@ -59,8 +63,10 @@ private XRpcStruct MetaWeblogNewMediaObject( XRpcStruct file, UrlHelper url) { - var user = _membershipService.ValidateUser(userName, password); - if (!_authorizationService.TryCheckAccess(Permissions.ManageOwnMedia, user, null)) { + List validationErrors; + var user = _membershipService.ValidateUser(userName, password, out validationErrors); + if (!_authorizationService.TryCheckAccess(Permissions.ManageOwnMedia, user, null) + && !_authorizationService.TryCheckAccess(Permissions.EditMediaContent, user, null)) { throw new OrchardCoreException(T("Access denied")); } @@ -73,25 +79,34 @@ private XRpcStruct MetaWeblogNewMediaObject( } // If the user only has access to his own folder, rewrite the folder name - if (!_authorizationService.TryCheckAccess(Permissions.ManageMediaContent, user, null)) { + if (!_authorizationService.TryCheckAccess(Permissions.EditMediaContent, user, null)) { directoryName = Path.Combine(_mediaLibraryService.GetRootedFolderPath(directoryName)); } + var filename = Path.GetFileName(name); + try { // delete the file if it already exists, e.g. an updated image in a blog post // it's safe to delete the file as each content item gets a specific folder - _mediaLibraryService.DeleteFile(directoryName, Path.GetFileName(name)); + _mediaLibraryService.DeleteFile(directoryName, filename); } catch { // current way to delete a file if it exists } - string publicUrl = _mediaLibraryService.UploadMediaFile(directoryName, Path.GetFileName(name), bits); - var mediaPart = _mediaLibraryService.ImportMedia(directoryName, Path.GetFileName(name)); - try { - _contentManager.Create(mediaPart); - } - catch { + string publicUrl = _mediaLibraryService.UploadMediaFile(directoryName, filename, bits); + + var settings = _orchardServices.WorkContext.CurrentSite.As(); + + // skip file if the allowed extensions is defined and doesn't match + if (settings.IsFileAllowed(filename)) { + var mediaPart = _mediaLibraryService.ImportMedia(directoryName, filename); + + try { + _contentManager.Create(mediaPart); + } + catch { + } } return new XRpcStruct() // Some clients require all optional attributes to be declared Wordpress responds in this way as well. diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Settings/MediaLibraryPickerFieldLocalizationEditorEvents.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Settings/MediaLibraryPickerFieldLocalizationEditorEvents.cs new file mode 100644 index 00000000000..66950d8a9de --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Settings/MediaLibraryPickerFieldLocalizationEditorEvents.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Globalization; +using Orchard.ContentManagement; +using Orchard.ContentManagement.MetaData; +using Orchard.ContentManagement.MetaData.Builders; +using Orchard.ContentManagement.MetaData.Models; +using Orchard.ContentManagement.ViewModels; +using Orchard.Environment.Extensions; + +namespace Orchard.MediaLibrary.Settings { + [OrchardFeature("Orchard.MediaLibrary.LocalizationExtensions")] + public class MediaLibraryPickerFieldLocalizationEditorEvents : ContentDefinitionEditorEventsBase { + + public override IEnumerable PartFieldEditor(ContentPartFieldDefinition definition) { + if (definition.FieldDefinition.Name == "MediaLibraryPickerField") { + var model = definition.Settings.GetModel(); + yield return DefinitionTemplate(model); + } + } + + public override IEnumerable PartFieldEditorUpdate(ContentPartFieldDefinitionBuilder builder, IUpdateModel updateModel) { + if (builder.FieldType != "MediaLibraryPickerField") { + yield break; + } + + var model = new MediaLibraryPickerFieldLocalizationSettings(); + if (updateModel.TryUpdateModel(model, "MediaLibraryPickerFieldLocalizationSettings", null, null)) { + builder.WithSetting("MediaLibraryPickerFieldLocalizationSettings.TryToLocalizeMedia", model.TryToLocalizeMedia.ToString(CultureInfo.InvariantCulture)); + builder.WithSetting("MediaLibraryPickerFieldLocalizationSettings.RemoveItemsWithoutLocalization", model.RemoveItemsWithoutLocalization.ToString(CultureInfo.InvariantCulture)); + builder.WithSetting("MediaLibraryPickerFieldLocalizationSettings.RemoveItemsWithNoLocalizationPart", model.RemoveItemsWithNoLocalizationPart.ToString(CultureInfo.InvariantCulture)); + } + + yield return DefinitionTemplate(model); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Settings/MediaLibraryPickerFieldLocalizationSettings.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Settings/MediaLibraryPickerFieldLocalizationSettings.cs new file mode 100644 index 00000000000..a683717740e --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Settings/MediaLibraryPickerFieldLocalizationSettings.cs @@ -0,0 +1,17 @@ +using Orchard.Environment.Extensions; + +namespace Orchard.MediaLibrary.Settings { + [OrchardFeature("Orchard.MediaLibrary.LocalizationExtensions")] + public class MediaLibraryPickerFieldLocalizationSettings { + + public MediaLibraryPickerFieldLocalizationSettings() { + TryToLocalizeMedia = true; + RemoveItemsWithoutLocalization = false; + RemoveItemsWithNoLocalizationPart = false; + + } + public bool TryToLocalizeMedia { get; set; } + public bool RemoveItemsWithoutLocalization { get; set; } + public bool RemoveItemsWithNoLocalizationPart { get; set; } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/media-library-picker-admin.css b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/media-library-picker-admin.css index 5313f9180f6..4aef7a4d6a1 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/media-library-picker-admin.css +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/media-library-picker-admin.css @@ -32,6 +32,12 @@ clear: both; } + .media-library-picker .media-thumbnail-image { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TRSkVB6sUcchQnSyIijhKFYtgobQVWnUwufQLmjQkKS6OgmvBwY/FqoOLs64OroIg+AHi5Oik6CIl/i8ptIjx4Lgf7+497t4BQqPCVLNrAlA1y0jFY2I2tyr2vEJAGAEMYVBipp5IL2bgOb7u4ePrXZRneZ/7c/QpeZMBPpF4jumGRbxBPLNp6Zz3iUOsJCnE58TjBl2Q+JHrsstvnIsOCzwzZGRS88QhYrHYwXIHs5KhEk8TRxRVo3wh67LCeYuzWqmx1j35C4N5bSXNdZojiGMJCSQhQkYNZVRgIUqrRoqJFO3HPPzDjj9JLplcZTByLKAKFZLjB/+D392ahalJNykYA7pfbPtjFOjZBZp12/4+tu3mCeB/Bq60tr/aAGY/Sa+3tcgR0L8NXFy3NXkPuNwBwk+6ZEiO5KcpFArA+xl9Uw4YuAUCa25vrX2cPgAZ6mr5Bjg4BMaKlL3u8e7ezt7+PdPq7wdPt3KZgxNbzAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAPFJREFUeNrt3LENhDAQRcHlsExA/03SAMjY5mI6YKV5HXxPsJmX4zieSF6tNfZ9j1JK6h3XdcUv9KmAABEQIAICRECACAgQAREQIAICRECACAgQAREQIAICRECACAgQAREQIAICRECACAgQAREQIAICRECACAgQAdGrUmtNP2Jd15hzRu89/Zblvu/0P8rNOaO1FmOM1Du2bYuS/Vu8iIjee4wxorWWHsQNcdQFBIiAABEQIAICREAEBIiAABEQIAICREAEBIiAABEQIAICREAEBIiAABEQIAICREAEBIiAABEQIAICRED0ajnP8/EM3+kPz+EneeiZXCUAAAAASUVORK5CYII="); + background-size: 15%; + background-repeat: repeat; + } + .overlay { position: absolute; bottom: 20px; @@ -42,15 +48,36 @@ text-align: right; font-size: 12px; opacity: 0.6; + height: 40px; +} +.thumbnail .overlay { + height: 40px; + overflow: hidden; +} +.thumbnail .overlay { + height: 40px; + overflow: hidden; +} +.thumbnail .overlay { + height: 40px; + overflow: hidden; } .overlay h3 { padding-right:5px; font-size: 12px; - height: 40px; overflow: hidden; } +.thumbnail .overlay h3 { + height: 1rem; + white-space: nowrap; + text-overflow: ellipsis; +} +.overlay .publication-status { + padding-right:5px; + overflow: hidden; +} .media-thumbnail { width: 120px; height: 120px; diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/menu.media-library-admin.css b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/menu.media-library-admin.css index a1076ccb1a3..dbab41574bd 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/menu.media-library-admin.css +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/menu.media-library-admin.css @@ -6,4 +6,10 @@ background-position:0 -30px !important; } .summary .media-thumbnail { display: inline-block; +} + +.summary .media-thumbnail-image { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TRSkVB6sUcchQnSyIijhKFYtgobQVWnUwufQLmjQkKS6OgmvBwY/FqoOLs64OroIg+AHi5Oik6CIl/i8ptIjx4Lgf7+497t4BQqPCVLNrAlA1y0jFY2I2tyr2vEJAGAEMYVBipp5IL2bgOb7u4ePrXZRneZ/7c/QpeZMBPpF4jumGRbxBPLNp6Zz3iUOsJCnE58TjBl2Q+JHrsstvnIsOCzwzZGRS88QhYrHYwXIHs5KhEk8TRxRVo3wh67LCeYuzWqmx1j35C4N5bSXNdZojiGMJCSQhQkYNZVRgIUqrRoqJFO3HPPzDjj9JLplcZTByLKAKFZLjB/+D392ahalJNykYA7pfbPtjFOjZBZp12/4+tu3mCeB/Bq60tr/aAGY/Sa+3tcgR0L8NXFy3NXkPuNwBwk+6ZEiO5KcpFArA+xl9Uw4YuAUCa25vrX2cPgAZ6mr5Bjg4BMaKlL3u8e7ezt7+PdPq7wdPt3KZgxNbzAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAPFJREFUeNrt3LENhDAQRcHlsExA/03SAMjY5mI6YKV5HXxPsJmX4zieSF6tNfZ9j1JK6h3XdcUv9KmAABEQIAICRECACAgQAREQIAICRECACAgQAREQIAICRECACAgQAREQIAICRECACAgQAREQIAICRECACAgQAdGrUmtNP2Jd15hzRu89/Zblvu/0P8rNOaO1FmOM1Du2bYuS/Vu8iIjee4wxorWWHsQNcdQFBIiAABEQIAICREAEBIiAABEQIAICREAEBIiAABEQIAICREAEBIiAABEQIAICREAEBIiAABEQIAICRED0ajnP8/EM3+kPz+EneeiZXCUAAAAASUVORK5CYII="); + background-size: 15%; + background-repeat: repeat; } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/orchard-medialibrary-admin.css b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/orchard-medialibrary-admin.css index 9831fb6a73b..c93c2f202c2 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/orchard-medialibrary-admin.css +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Styles/orchard-medialibrary-admin.css @@ -267,13 +267,18 @@ #media-library-main-list .media-thumbnail { width: 200px; height: 200px; - overflow:hidden; + overflow: hidden; +} +#media-library-main-editor-focus .media-item-summary-admin img { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TRSkVB6sUcchQnSyIijhKFYtgobQVWnUwufQLmjQkKS6OgmvBwY/FqoOLs64OroIg+AHi5Oik6CIl/i8ptIjx4Lgf7+497t4BQqPCVLNrAlA1y0jFY2I2tyr2vEJAGAEMYVBipp5IL2bgOb7u4ePrXZRneZ/7c/QpeZMBPpF4jumGRbxBPLNp6Zz3iUOsJCnE58TjBl2Q+JHrsstvnIsOCzwzZGRS88QhYrHYwXIHs5KhEk8TRxRVo3wh67LCeYuzWqmx1j35C4N5bSXNdZojiGMJCSQhQkYNZVRgIUqrRoqJFO3HPPzDjj9JLplcZTByLKAKFZLjB/+D392ahalJNykYA7pfbPtjFOjZBZp12/4+tu3mCeB/Bq60tr/aAGY/Sa+3tcgR0L8NXFy3NXkPuNwBwk+6ZEiO5KcpFArA+xl9Uw4YuAUCa25vrX2cPgAZ6mr5Bjg4BMaKlL3u8e7ezt7+PdPq7wdPt3KZgxNbzAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAPFJREFUeNrt3LENhDAQRcHlsExA/03SAMjY5mI6YKV5HXxPsJmX4zieSF6tNfZ9j1JK6h3XdcUv9KmAABEQIAICRECACAgQAREQIAICRECACAgQAREQIAICRECACAgQAREQIAICRECACAgQAREQIAICRECACAgQAdGrUmtNP2Jd15hzRu89/Zblvu/0P8rNOaO1FmOM1Du2bYuS/Vu8iIjee4wxorWWHsQNcdQFBIiAABEQIAICREAEBIiAABEQIAICREAEBIiAABEQIAICREAEBIiAABEQIAICREAEBIiAABEQIAICRED0ajnP8/EM3+kPz+EneeiZXCUAAAAASUVORK5CYII="); + background-size: 15%; + background-repeat: repeat; } #media-library-main-selection .media-thumbnail { width: 120px; height: 120px; - overflow:hidden; + overflow: hidden; } .media-thumbnail-o-embed { @@ -294,6 +299,9 @@ -o-background-size: cover; -webkit-background-size: cover; background-size: cover; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TRSkVB6sUcchQnSyIijhKFYtgobQVWnUwufQLmjQkKS6OgmvBwY/FqoOLs64OroIg+AHi5Oik6CIl/i8ptIjx4Lgf7+497t4BQqPCVLNrAlA1y0jFY2I2tyr2vEJAGAEMYVBipp5IL2bgOb7u4ePrXZRneZ/7c/QpeZMBPpF4jumGRbxBPLNp6Zz3iUOsJCnE58TjBl2Q+JHrsstvnIsOCzwzZGRS88QhYrHYwXIHs5KhEk8TRxRVo3wh67LCeYuzWqmx1j35C4N5bSXNdZojiGMJCSQhQkYNZVRgIUqrRoqJFO3HPPzDjj9JLplcZTByLKAKFZLjB/+D392ahalJNykYA7pfbPtjFOjZBZp12/4+tu3mCeB/Bq60tr/aAGY/Sa+3tcgR0L8NXFy3NXkPuNwBwk+6ZEiO5KcpFArA+xl9Uw4YuAUCa25vrX2cPgAZ6mr5Bjg4BMaKlL3u8e7ezt7+PdPq7wdPt3KZgxNbzAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAPFJREFUeNrt3LENhDAQRcHlsExA/03SAMjY5mI6YKV5HXxPsJmX4zieSF6tNfZ9j1JK6h3XdcUv9KmAABEQIAICRECACAgQAREQIAICRECACAgQAREQIAICRECACAgQAREQIAICRECACAgQAREQIAICRECACAgQAdGrUmtNP2Jd15hzRu89/Zblvu/0P8rNOaO1FmOM1Du2bYuS/Vu8iIjee4wxorWWHsQNcdQFBIiAABEQIAICREAEBIiAABEQIAICREAEBIiAABEQIAICREAEBIiAABEQIAICREAEBIiAABEQIAICRED0ajnP8/EM3+kPz+EneeiZXCUAAAAASUVORK5CYII="); + background-size: 15%; + background-repeat: repeat; } .media-thumbnail-video { diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml index 159d6c11991..ddf4bfaa888 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml @@ -22,6 +22,11 @@ @T("Create Folder") @Display(Model.CustomActionsShapes) +
        @@ -52,9 +57,12 @@

        @T("PROPERTIES")

        -
        - -
        +
        +
        + +
        + @Html.AntiForgeryTokenOrchard() +
        @@ -105,6 +113,7 @@ var mediaLibrarySettings = { cloneConfirmationMessage: '@HttpUtility.JavaScriptStringEncode(T("Are you sure you want to clone this media item ?").Text)', replaceConfirmationMessage: '@HttpUtility.JavaScriptStringEncode(T("Are you sure you want to replace this media item ?").Text)', errorMessage: '@HttpUtility.JavaScriptStringEncode(T("An unexpected error occured, please refresh the page and try again.").Text)', + unauthorizedMessage: '@HttpUtility.JavaScriptStringEncode(T("Access denied").Text)', antiForgeryToken: '@Html.AntiForgeryTokenValueOrchard()', childFolders: (@Display.Partial(TemplateName: "ChildFolders", Model: viewModel.ChildFoldersViewModel))['childFolders'] }; @@ -114,7 +123,7 @@ var mediaLibrarySettings = {
      • - +
        diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/MediaItems.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/MediaItems.cshtml index d7238347a33..7b5bd07e065 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/MediaItems.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/MediaItems.cshtml @@ -1,4 +1,6 @@ @using Orchard.Utility.Extensions +@using Orchard.Localization.Models +@using Orchard.ContentManagement @model Orchard.MediaLibrary.ViewModels.MediaManagerMediaItemsViewModel @{ Response.ContentType = "text/json"; @@ -6,21 +8,21 @@ new { mediaItemsCount = Model.MediaItemsCount, mediaItems = Model.MediaItems.Select(x => new { - id = x.MediaPart.Id, - contentType = x.MediaPart.ContentItem.ContentType, - contentTypeClass = x.MediaPart.ContentItem.ContentType.HtmlClassify(), + id = x.MediaPart.Id, + contentType = x.MediaPart.ContentItem.ContentType, + contentTypeClass = x.MediaPart.ContentItem.ContentType.HtmlClassify(), title = x.MediaPart.Title, published = x.MediaPart.ContentItem.VersionRecord.Published, - alternateText = x.MediaPart.AlternateText, - caption = x.MediaPart.Caption, - resource = x.MediaPart.MediaUrl, - mimeType = x.MediaPart.MimeType, - mimeTypeClass = x.MediaPart.MimeType.HtmlClassify(), + alternateText = x.MediaPart.AlternateText, + caption = x.MediaPart.Caption, + resource = x.MediaPart.MediaUrl, + mimeType = x.MediaPart.MimeType, + mimeTypeClass = x.MediaPart.MimeType.HtmlClassify(), thumbnail = Display(x.Shape).ToString(), - editLink = Url.ItemEditUrl(x.MediaPart) + editLink = Url.ItemEditUrl(x.MediaPart), + localization = (((dynamic)x.MediaPart.ContentItem).LocalizationPart != null && ((dynamic)x.MediaPart.ContentItem).LocalizationPart.Culture != null) ? ((dynamic)x.MediaPart.ContentItem).LocalizationPart.CultureField.Value.Culture : "" }).ToArray(), folderPath = Model.FolderPath })) } - \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/ClientStorage/Index.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/ClientStorage/Index.cshtml index cf1d393dbc7..f3df7de41e1 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/ClientStorage/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/ClientStorage/Index.cshtml @@ -1,4 +1,7 @@ -@model Orchard.MediaLibrary.ViewModels.ImportMediaViewModel +@using Orchard.MediaLibrary.Models; +@using Orchard.ContentManagement; + +@model Orchard.MediaLibrary.ViewModels.ImportMediaViewModel @@ -12,6 +15,8 @@ Script.Require("jQueryFileUpload").AtFoot(); Script.Require("Knockout").AtFoot(); + + var settings = WorkContext.CurrentSite.As(); } @Display.Metas() @@ -23,7 +28,7 @@
        @T("Click here, Drop files or Paste images")
        - multiple="multiple" } > + multiple="multiple" } />
        • @@ -36,9 +41,9 @@
        - + @using (Script.Foot()) { - + } - + @Display.FootScripts() \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/DefinitionTemplates/MediaLibraryPickerFieldLocalizationSettings.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/DefinitionTemplates/MediaLibraryPickerFieldLocalizationSettings.cshtml new file mode 100644 index 00000000000..c98bb7acf0d --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/DefinitionTemplates/MediaLibraryPickerFieldLocalizationSettings.cshtml @@ -0,0 +1,15 @@ +@model Orchard.MediaLibrary.Settings.MediaLibraryPickerFieldLocalizationSettings + +
        + @Html.CheckBoxFor(m => m.TryToLocalizeMedia) + + @T("Check to attempt to replace media items selected in this field with their translation in the main ContentItem's culture. This only applies if the main ContentItem has a LocalizationPart.") +
        + @Html.CheckBoxFor(m => m.RemoveItemsWithoutLocalization) + + @T("Check to remove media items from the MediaLibraryPickerField when the items selected do not have a version in the correct culture (they have a LocalizationPart, but not a translation in the main ContentItem's culture).") + @Html.CheckBoxFor(m => m.RemoveItemsWithNoLocalizationPart) + + @T("Check to remove media items from the MediaLibraryPickerField when the items selected cannot be localized (do not have a LocalizationPart).") +
        +
        diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/EditorTemplates/Parts/MediaLibrary.MediaLibrarySettings.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/EditorTemplates/Parts/MediaLibrary.MediaLibrarySettings.cshtml index 82fdaf19cfa..dc07b9b1c2e 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/EditorTemplates/Parts/MediaLibrary.MediaLibrarySettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/EditorTemplates/Parts/MediaLibrary.MediaLibrarySettings.cshtml @@ -6,5 +6,8 @@ @Html.TextBoxFor(m => m.UploadAllowedFileTypeWhitelist, new { @class = "text large"}) @T("A comma separated list of file extensions, e.g., \".jpg, .avi, .txt\". Leave empty to accept any file types.") + + @Html.TextBoxFor(m => m.LimitConcurrentUploads, new { @class = "text medium"}) + @T("To limit the number of concurrent uploads, set this value to an integer greater than 0")
        \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/EditorTemplates/Parts/WebSearch.WebSearchSettings.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/EditorTemplates/Parts/WebSearch.WebSearchSettings.cshtml deleted file mode 100644 index b9ee02e801f..00000000000 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/EditorTemplates/Parts/WebSearch.WebSearchSettings.cshtml +++ /dev/null @@ -1,11 +0,0 @@ -@model Orchard.MediaLibrary.Models.WebSearchSettingsPart - -
        - @T("Web Search") -
        - @Html.TextBoxFor(m => m.ApiKey, new { @class = "text medium"}) - @T("Your private key.") -
        - - @T("Get a free API Key on {0}", Html.Raw("http://datamarket.azure.com/dataset/bing/search")) -
        \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Fields/MediaLibraryPicker.SummaryAdmin.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Fields/MediaLibraryPicker.SummaryAdmin.cshtml index bb012a14659..675b2ecb97b 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Fields/MediaLibraryPicker.SummaryAdmin.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Fields/MediaLibraryPicker.SummaryAdmin.cshtml @@ -8,7 +8,7 @@ string name = field.Name; var mediaParts = field.MediaParts; - var returnUrl = ViewContext.RequestContext.HttpContext.Request.ToUrlString(); + var returnUrl = ViewContext.RequestContext.HttpContext.Request.RawUrl; } @displayName:

        diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Localization.ContentTranslations.SummaryAdmin.ForMedia.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Localization.ContentTranslations.SummaryAdmin.ForMedia.cshtml new file mode 100644 index 00000000000..1cd119e0c1f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Localization.ContentTranslations.SummaryAdmin.ForMedia.cshtml @@ -0,0 +1,22 @@ +@using Orchard.Core.Contents; +@using Orchard.Localization.Models; +@if (AuthorizedFor(Permissions.PublishContent)) { + Style.Require("LocalizationAdmin"); + IEnumerable localizations = Model.Localizations; + var localizationLinks = Html.UnorderedList(localizations, (c, i) => Html.ItemEditLink(c.Culture.Culture, c, new { ReturnUrl = Request.UrlReferrer }), "localizations"); +

        + @if (Model.Culture != null) { +
        @T("Culture: {0}", Model.Culture)
        + } else { +
        @T("Culture: {0}", T("Undefined"))
        + } + @if (localizations.Count() > 0) + { +

        @T("Translations:")

        @localizationLinks
        + } + @if (Model.Culture != null && !((IEnumerable)Model.SiteCultures).All(c => c == Model.Culture || localizations.Any(l => c == l.Culture.Culture))) + { +
        @Html.ActionLink(T("+ New translation").Text, "Translate", "Admin", new { area = "Orchard.Localization", id = Model.MasterId, ReturnUrl = Request.UrlReferrer }, new { itemprop = "UnsafeUrl" })
        + } +
        +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/LocalizedMedia/MediaItems.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/LocalizedMedia/MediaItems.cshtml new file mode 100644 index 00000000000..65966a307e4 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/LocalizedMedia/MediaItems.cshtml @@ -0,0 +1,27 @@ +@using Orchard.Utility.Extensions + +@model Orchard.MediaLibrary.ViewModels.MediaManagerMediaItemsViewModel +@{ + Response.ContentType = "text/json"; + @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject( + new { + mediaItemsCount = Model.MediaItemsCount, + mediaItems = Model.MediaItems.Select(x => new { + id = x.MediaPart.Id, + contentType = x.MediaPart.ContentItem.ContentType, + contentTypeClass = x.MediaPart.ContentItem.ContentType.HtmlClassify(), + title = x.MediaPart.Title, + published = x.MediaPart.ContentItem.VersionRecord.Published, + alternateText = x.MediaPart.AlternateText, + caption = x.MediaPart.Caption, + resource = x.MediaPart.MediaUrl, + mimeType = x.MediaPart.MimeType, + mimeTypeClass = x.MediaPart.MimeType.HtmlClassify(), + thumbnail = Display(x.Shape).ToString(), + editLink = Url.ItemEditUrl(x.MediaPart), + localization = (((dynamic)x.MediaPart.ContentItem).LocalizationPart != null && ((dynamic)x.MediaPart.ContentItem).LocalizationPart.Culture != null) ? ((dynamic)x.MediaPart.ContentItem).LocalizationPart.CultureField.Value.Culture : "" + }).ToArray(), + folderPath = Model.FolderPath + })) +} + diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Media-Audio.Thumbnail.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Media-Audio.Thumbnail.cshtml index 9eba697f41c..6e73dca6360 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Media-Audio.Thumbnail.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Media-Audio.Thumbnail.cshtml @@ -10,4 +10,4 @@ } @* Don't render the audio tag as thumbnails or the whole file is downloaded automatically by browsers *@ -
        \ No newline at end of file +
        \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Media-Video.Thumbnail.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Media-Video.Thumbnail.cshtml index 37550c9c270..fbe03af50bd 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Media-Video.Thumbnail.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Media-Video.Thumbnail.cshtml @@ -10,4 +10,4 @@ } @* Don't render the video tag as thumbnails or the whole file is downloaded automatically by browsers *@ -
        +
        diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/MediaLibraryPicker.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/MediaLibraryPicker.cshtml index eab2cad244a..9c4fa05c312 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/MediaLibraryPicker.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/MediaLibraryPicker.cshtml @@ -1,5 +1,6 @@ @using Orchard.ContentManagement -@using Orchard.Utility.Extensions; +@using Orchard.Localization.Models +@using Orchard.Utility.Extensions @{ Style.Include("media-library-picker-admin.css"); @@ -8,12 +9,12 @@ Script.Require("jQueryColorBox").AtFoot(); Script.Include("media-library-picker.js").AtFoot(); - var fieldName = (string) Model.FieldName; - var displayName = (string) Model.DisplayName; + var fieldName = (string)Model.FieldName; + var displayName = (string)Model.DisplayName; var multiple = (bool)(Model.Multiple ?? false); var required = (bool)(Model.Required ?? false); - var hint = (string) Model.Hint; - var promptOnNavigate = (bool) (Model.PromptOnNavigate ?? true); + var hint = (string)Model.Hint; + var promptOnNavigate = (bool)(Model.PromptOnNavigate ?? true); var showSaveWarning = (bool)(Model.ShowSaveWarning); var contentItems = (IEnumerable)Model.ContentItems ?? Enumerable.Empty(); var contentManager = WorkContext.Resolve(); @@ -31,10 +32,10 @@ data-return-url="@HttpUtility.JavaScriptStringEncode(Request.RawUrl)" data-prompt-on-navigate="@promptOnNavigate.ToString().ToLower()" data-show-save-warning="@showSaveWarning.ToString().ToLower()"> - +
        @T("You need to save your changes.")
        -
          +
            @foreach (var contentItem in contentItems) { var editRouteValues = contentManager.GetItemMetadata(contentItem).EditorRouteValues; var editUrl = Url.Action( @@ -45,14 +46,29 @@
            @Display(BuildDisplay(contentItem, "Thumbnail"))
            -

            @Html.ItemDisplayText(contentItem)

            +

            @Html.ItemDisplayText(contentItem)

            +

            + @(contentItem.IsPublished() ? "" : T("Draft").Text) + @{ + var localizationPart = contentItem.As(); + if (localizationPart != null && localizationPart.Culture != null) { + @(string.Format(" ({0})", localizationPart.Culture.Culture)) + } + } +

        - @T("Remove")@T(" | ") - @T("Edit") +
      • - } + }
        diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-Audio.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-Audio.cshtml new file mode 100644 index 00000000000..ee01f976c81 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-Audio.cshtml @@ -0,0 +1 @@ +@Display(New.Localization_ContentTranslations_SummaryAdmin_ForMedia(Localizations: Model.Localizations, Culture: Model.Culture,SiteCultures: Model.SiteCultures, MasterId:Model.MasterId)) diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-Document.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-Document.cshtml new file mode 100644 index 00000000000..ee01f976c81 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-Document.cshtml @@ -0,0 +1 @@ +@Display(New.Localization_ContentTranslations_SummaryAdmin_ForMedia(Localizations: Model.Localizations, Culture: Model.Culture,SiteCultures: Model.SiteCultures, MasterId:Model.MasterId)) diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-Image.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-Image.cshtml new file mode 100644 index 00000000000..ee01f976c81 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-Image.cshtml @@ -0,0 +1 @@ +@Display(New.Localization_ContentTranslations_SummaryAdmin_ForMedia(Localizations: Model.Localizations, Culture: Model.Culture,SiteCultures: Model.SiteCultures, MasterId:Model.MasterId)) diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-OEmbed.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-OEmbed.cshtml new file mode 100644 index 00000000000..ee01f976c81 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-OEmbed.cshtml @@ -0,0 +1 @@ +@Display(New.Localization_ContentTranslations_SummaryAdmin_ForMedia(Localizations: Model.Localizations, Culture: Model.Culture,SiteCultures: Model.SiteCultures, MasterId:Model.MasterId)) diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-VectorImage.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-VectorImage.cshtml new file mode 100644 index 00000000000..ee01f976c81 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-VectorImage.cshtml @@ -0,0 +1 @@ +@Display(New.Localization_ContentTranslations_SummaryAdmin_ForMedia(Localizations: Model.Localizations, Culture: Model.Culture,SiteCultures: Model.SiteCultures, MasterId:Model.MasterId)) diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-Video.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-Video.cshtml new file mode 100644 index 00000000000..ee01f976c81 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Localization.ContentTranslations.SummaryAdmin-Video.cshtml @@ -0,0 +1 @@ +@Display(New.Localization_ContentTranslations_SummaryAdmin_ForMedia(Localizations: Model.Localizations, Culture: Model.Culture,SiteCultures: Model.SiteCultures, MasterId:Model.MasterId)) diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Media.Actions.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Media.Actions.cshtml index e65370b4d4c..1bdc0f1e673 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Media.Actions.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/Media.Actions.cshtml @@ -4,10 +4,12 @@ @{ ContentItem contentItem = Model.ContentItem; var draftable = contentItem.TypeDefinition.Settings.GetModel().Draftable; + var media = contentItem.As(); + var mediaService = WorkContext.Resolve(); }
        - @if (Authorizer.Authorize(Permissions.EditContent, contentItem)) { + @if (mediaService.CheckMediaFolderPermission(Orchard.MediaLibrary.Permissions.EditMediaContent, media.FolderPath)) { @Html.Link(T("Edit").Text, Url.ItemEditUrl(contentItem), new { @class = "button", id = "edit-media-link" }) } @if (Authorizer.Authorize(Permissions.PublishContent, contentItem) && draftable) { diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/MediaLibraryLocalization.Actions.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/MediaLibraryLocalization.Actions.cshtml new file mode 100644 index 00000000000..aca3a31797e --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/MediaLibraryLocalization.Actions.cshtml @@ -0,0 +1,39 @@ + +
        + + +
        + +@using (Script.Foot()) { + + +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Web.config b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Web.config index bfeea149d0f..68ff8758d7e 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Web.config +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Web.config @@ -7,7 +7,7 @@ - + @@ -21,14 +21,17 @@ + + + - + - + @@ -36,25 +39,41 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/packages.config b/src/Orchard.Web/Modules/Orchard.MediaLibrary/packages.config index 1ea27eef99b..d8ef6eca5c4 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/packages.config +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/packages.config @@ -1,8 +1,9 @@  - - - - - - \ No newline at end of file + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.MediaPicker/Module.txt b/src/Orchard.Web/Modules/Orchard.MediaPicker/Module.txt index 796dc67251a..8806e892be9 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaPicker/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.MediaPicker/Module.txt @@ -4,7 +4,7 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net Version: 1.8 -OrchardVersion: 1.9 +OrchardVersion: 1.10.3 LifecycleStatus: Deprecated Description: UI for browsing for, uploading, or selecting an image for an HTML editor. Dependencies: Orchard.Media, Orchard.Resources diff --git a/src/Orchard.Web/Modules/Orchard.MediaPicker/Orchard.MediaPicker.csproj b/src/Orchard.Web/Modules/Orchard.MediaPicker/Orchard.MediaPicker.csproj index eed4e0888d0..89bb5c6414c 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaPicker/Orchard.MediaPicker.csproj +++ b/src/Orchard.Web/Modules/Orchard.MediaPicker/Orchard.MediaPicker.csproj @@ -12,8 +12,8 @@ Properties Orchard.MediaPicker Orchard.MediaPicker - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,9 @@ + + + true @@ -49,10 +52,12 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -67,29 +72,23 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -123,12 +122,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {D9A7B330-CD22-4DA1-A95A-8DE1982AD8EB} @@ -142,7 +141,9 @@ - + + + @@ -182,7 +183,7 @@ - + 10.0 @@ -208,7 +209,7 @@ --> - + @@ -222,10 +223,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.MediaPicker/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.MediaPicker/Properties/AssemblyInfo.cs index dce5d992711..b29969d090a 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaPicker/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaPicker/Properties/AssemblyInfo.cs @@ -31,6 +31,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.MediaPicker/Views/Admin/Tab_Gallery.cshtml b/src/Orchard.Web/Modules/Orchard.MediaPicker/Views/Admin/Tab_Gallery.cshtml index adb7cdb2e05..5106df266b3 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaPicker/Views/Admin/Tab_Gallery.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaPicker/Views/Admin/Tab_Gallery.cshtml @@ -7,7 +7,7 @@ @helper FolderLink(string folderName, string mediaPath) { // querystring values need to persist after a new GET when clicking on the media browser's // folders for navigation. - @Html.ActionLink(folderName, "Index", null, null, null, "tab=1", new { + @Html.ActionLink(folderName, "Index", null, null, null, "tab-gallery", new { callback = Request["callback"], uploadpath = Request["uploadpath"], editmode = Request["editmode"], diff --git a/src/Orchard.Web/Modules/Orchard.MediaPicker/Web.config b/src/Orchard.Web/Modules/Orchard.MediaPicker/Web.config index a3cb5df907e..baf3b31252b 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaPicker/Web.config +++ b/src/Orchard.Web/Modules/Orchard.MediaPicker/Web.config @@ -7,7 +7,7 @@ - + @@ -21,39 +21,58 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.MediaPicker/packages.config b/src/Orchard.Web/Modules/Orchard.MediaPicker/packages.config index 6729ced4977..1c55d6960bb 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaPicker/packages.config +++ b/src/Orchard.Web/Modules/Orchard.MediaPicker/packages.config @@ -1,7 +1,8 @@  - - - - - \ No newline at end of file + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Controllers/AdminController.cs index 9c92d78940e..ad6ab16f245 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Controllers/AdminController.cs @@ -88,7 +88,7 @@ public ActionResult Index(FormCollection input) { if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to manage media profiles"))) return new HttpUnauthorizedResult(); - var viewModel = new AdminIndexViewModel {ImageProfiles = new List(), Options = new AdminIndexOptions()}; + var viewModel = new AdminIndexViewModel { ImageProfiles = new List(), Options = new AdminIndexOptions() }; UpdateModel(viewModel); var checkedItems = viewModel.ImageProfiles.Where(c => c.IsChecked); @@ -133,7 +133,7 @@ public ActionResult Edit(int id) { Category = f.Category, Type = f.Type, FilterRecordId = filter.Id, - DisplayText = String.IsNullOrWhiteSpace(filter.Description) ? f.Display(new FilterContext {State = FormParametersHelper.ToDynamic(filter.State)}).Text : filter.Description + DisplayText = String.IsNullOrWhiteSpace(filter.Description) ? f.Display(new FilterContext { State = FormParametersHelper.ToDynamic(filter.State) }).Text : filter.Description }); } } @@ -154,7 +154,7 @@ public ActionResult Delete(int id) { return HttpNotFound(); } - Services.ContentManager.Remove(profile.ContentItem); + _profileService.DeleteImageProfile(id); Services.Notifier.Success(T("Image Profile {0} deleted", profile.Name)); return RedirectToAction("Index"); @@ -175,7 +175,7 @@ public ActionResult Move(string direction, int id, int filterId) { throw new ArgumentException("direction"); } - return RedirectToAction("Edit", new {id}); + return RedirectToAction("Edit", new { id }); } public ActionResult Preview(int id) { @@ -185,6 +185,36 @@ public ActionResult Preview(int id) { throw new NotImplementedException(); } + [HttpPost] + public ActionResult Purge(int id) { + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to manage media profiles"))) + return new HttpUnauthorizedResult(); + + if (_profileService.PurgeImageProfile(id)) { + Services.Notifier.Information(T("The Image Profile has been purged")); + } + else { + Services.Notifier.Warning(T("Unable to purge the Image Profile, it may already have been purged")); + } + + return RedirectToAction("Index"); + } + + [HttpPost] + public ActionResult PurgeObsolete() { + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to manage media profiles"))) + return new HttpUnauthorizedResult(); + + if (_profileService.PurgeObsoleteImageProfiles()) { + Services.Notifier.Information(T("The obsolete Image Profiles have been purged")); + } + else { + Services.Notifier.Warning(T("Unable to purge the obsolete Image Profiles")); + } + + return RedirectToAction("Index"); + } + bool IUpdateModel.TryUpdateModel(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) { return TryUpdateModel(model, prefix, includeProperties, excludeProperties); } diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Models/ImageProfilePart.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Models/ImageProfilePart.cs index a8de5d8fe8a..1b432036b3c 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Models/ImageProfilePart.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Models/ImageProfilePart.cs @@ -24,4 +24,4 @@ public IList FileNames { get { return Record.FileNames; } } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Module.txt b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Module.txt index eceed599fb1..c6cdefc65f8 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: John Murdock, Sébastien Ros Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Module for processing Media e.g. image resizing Category: Media Dependencies: Orchard.Forms \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Orchard.MediaProcessing.csproj b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Orchard.MediaProcessing.csproj index 454cf9fd02a..64566bec40f 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Orchard.MediaProcessing.csproj +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Orchard.MediaProcessing.csproj @@ -12,8 +12,8 @@ Properties Orchard.MediaProcessing Orchard.MediaProcessing - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,9 @@ + + + true @@ -49,14 +52,15 @@ false - - ..\..\..\packages\ImageResizer.3.4.3\lib\ImageResizer.dll - True + + ..\..\..\packages\ImageResizer.4.2.8\lib\net45\ImageResizer.dll + + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -72,29 +76,23 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -111,17 +109,21 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {642A49D7-8752-4177-80D6-BFBBCFAD3DE0} Orchard.Forms + + {73a7688a-5bd3-4f7e-adfa-ce36c5a10e3b} + Orchard.MediaLibrary + {6f759635-13d7-4e94-bcc9-80445d63f117} Orchard.Tokens @@ -188,7 +190,7 @@ - + 10.0 @@ -214,7 +216,7 @@ --> - + @@ -228,7 +230,7 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Properties/AssemblyInfo.cs index 986ca9bfdc7..d91e68576c4 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Properties/AssemblyInfo.cs @@ -31,6 +31,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/ResizeFilter.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/ResizeFilter.cs index 99db8060a30..580a3a95091 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/ResizeFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Providers/Filters/ResizeFilter.cs @@ -32,6 +32,7 @@ public void ApplyFilter(FilterContext context) { string mode = context.State.Mode; string alignment = context.State.Alignment; string padcolor = context.State.PadColor; + string scale = context.State.Scale; var settings = new ResizeSettings { Mode = FitMode.Max, @@ -70,6 +71,13 @@ public void ApplyFilter(FilterContext context) { } } + switch (scale) { + case "downscaleOnly": settings.Scale = ScaleMode.DownscaleOnly; break; + case "upscaleOnly": settings.Scale = ScaleMode.UpscaleOnly; break; + case "both": settings.Scale = ScaleMode.Both; break; + case "upscaleCanvas": settings.Scale = ScaleMode.UpscaleCanvas; break; + } + var result = new MemoryStream(); if (context.Media.CanSeek) { context.Media.Seek(0, SeekOrigin.Begin); @@ -82,10 +90,10 @@ public LocalizedString DisplayFilter(FilterContext context) { string mode = context.State.Mode; switch (mode) { - case "pad": return T("Pad to {0}x{1}", context.State.Height, context.State.Width); - case "crop": return T("Crop to {0}x{1}", context.State.Height, context.State.Width); - case "stretch": return T("Stretch to {0}x{1}", context.State.Height, context.State.Width); - default: return T("Resize to {0}x{1}", context.State.Height, context.State.Width); + case "pad": return T("Pad to {0} x {1}", context.State.Width, context.State.Height); + case "crop": return T("Crop to {0} x {1}", context.State.Width, context.State.Height); + case "stretch": return T("Stretch to {0} x {1}", context.State.Width, context.State.Height); + default: return T("Resize to {0} x {1}", context.State.Width, context.State.Height); } } @@ -135,7 +143,13 @@ public void Describe(DescribeContext context) { Title: T("Pad Color"), Value: "", Description: T("The background color to use to pad the image e.g., #ffffff, red. Leave empty to keep transparency."), - Classes: new[] {"text small"}) + Classes: new[] {"text small"}), + _Scale: Shape.SelectList( + Id: "scale", Name: "Scale", + Title: T("Scale"), + Description: T("Select the scale mode which defines whether the image is allowed to upscale, downscale, both, or if only the canvas gets to be upscaled."), + Size: 1, + Multiple: false) ); f._Mode.Add(new SelectListItem { Value = "max", Text = T("Max").Text }); @@ -153,6 +167,11 @@ public void Describe(DescribeContext context) { f._Alignment.Add(new SelectListItem { Value = "bottomcenter", Text = T("Bottom Center").Text }); f._Alignment.Add(new SelectListItem { Value = "bottomright", Text = T("Bottom Right").Text }); + f._Scale.Add(new SelectListItem { Value = "downscaleOnly", Text = T("Downscale only").Text }); + f._Scale.Add(new SelectListItem { Value = "upscaleOnly", Text = T("Upscale only").Text }); + f._Scale.Add(new SelectListItem { Value = "both", Text = T("Both").Text }); + f._Scale.Add(new SelectListItem { Value = "upscaleCanvas", Text = T("Upscale canvas").Text }); + return f; }; diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/IImageProfileService.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/IImageProfileService.cs index e3a240f75f0..d8c77cc66bc 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/IImageProfileService.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/IImageProfileService.cs @@ -10,5 +10,12 @@ public interface IImageProfileService : IDependency { void DeleteImageProfile(int id); void MoveUp(int filterId); void MoveDown(int filterId); + bool PurgeImageProfile(int id); + bool PurgeObsoleteImageProfiles(); } -} \ No newline at end of file + + public static class ImageProfileServiceExtensions { + public static string GetNameHashCode(this IImageProfileService service, string name) => + name.GetHashCode().ToString("x").ToLowerInvariant(); + } +} diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileManager.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileManager.cs index c09d7bbfd71..68d4cf4a8e4 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileManager.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileManager.cs @@ -4,12 +4,12 @@ using System.IO; using System.Linq; using System.Net; -using System.Security.Cryptography; using System.Web; using Orchard.ContentManagement; using Orchard.FileSystems.Media; using Orchard.Forms.Services; using Orchard.Logging; +using Orchard.MediaLibrary.Models; using Orchard.MediaProcessing.Descriptors.Filter; using Orchard.MediaProcessing.Media; using Orchard.MediaProcessing.Models; @@ -44,7 +44,7 @@ public ImageProfileManager( public ILogger Logger { get; set; } - public string GetImageProfileUrl(string path, string profileName) { + public string GetImageProfileUrl(string path, string profileName) { return GetImageProfileUrl(path, profileName, null, new FilterRecord[] { }); } @@ -66,37 +66,41 @@ public string GetImageProfileUrl(string path, string profileName, ContentItem co // path is the publicUrl of the media, so it might contain url-encoded chars // try to load the processed filename from cache - var filePath = _fileNameProvider.GetFileName(profileName, System.Web.HttpUtility.UrlDecode(path)); + var filePath = _fileNameProvider.GetFileName(profileName, HttpUtility.UrlDecode(path)); bool process = false; - //after reboot the app cache is empty so we reload the image in the cache if it exists in the _Profiles folder - if (string.IsNullOrEmpty(filePath)) { - var profileFilePath = _storageProvider.Combine("_Profiles", FormatProfilePath(profileName, System.Web.HttpUtility.UrlDecode(path))); - - if (_storageProvider.FileExists(profileFilePath)) { - _fileNameProvider.UpdateFileName(profileName, System.Web.HttpUtility.UrlDecode(path), profileFilePath); - filePath = profileFilePath; + // Before checking everything else, ensure that the content item that needs to be processed has a ImagePart. + // If it's not the case (e.g. if media is a svg file), processing would throw a exception. + // If content item is null (it means it's not passed as a parameter of the ResizeMediaUrl call), + // this function processes the file like it did before this patch; + // this means it could possibly throw and log exceptions for svg files. + bool checkForProfile = (contentItem == null || contentItem.Has()); + + if (checkForProfile) { + //after reboot the app cache is empty so we reload the image in the cache if it exists in the _Profiles folder + if (string.IsNullOrEmpty(filePath)) { + var profileFilePath = _storageProvider.Combine("_Profiles", FormatProfilePath(profileName, HttpUtility.UrlDecode(path))); + + if (_storageProvider.FileExists(profileFilePath)) { + _fileNameProvider.UpdateFileName(profileName, HttpUtility.UrlDecode(path), profileFilePath); + filePath = profileFilePath; + } } - } - - // if the filename is not cached, process it - if (string.IsNullOrEmpty(filePath)) { - Logger.Debug("FilePath is null, processing required, profile {0} for image {1}", profileName, path); - process = true; - } + // if the filename is not cached, process it + if (string.IsNullOrEmpty(filePath)) { + Logger.Debug("FilePath is null, processing required, profile {0} for image {1}", profileName, path); + process = true; + } // the processd file doesn't exist anymore, process it - else if (!_storageProvider.FileExists(filePath)) { - Logger.Debug("Processed file no longer exists, processing required, profile {0} for image {1}", profileName, path); - - process = true; - } + else if (!_storageProvider.FileExists(filePath)) { + Logger.Debug("Processed file no longer exists, processing required, profile {0} for image {1}", profileName, path); - // if the original file is more recent, process it - else { - DateTime pathLastUpdated; - if (TryGetImageLastUpdated(path, out pathLastUpdated)) { + process = true; + } + // if the original file is more recent, process it + else if (TryGetImageLastUpdated(path, out DateTime pathLastUpdated)) { var filePathLastUpdated = _storageProvider.GetFile(filePath).GetLastUpdated(); if (pathLastUpdated > filePathLastUpdated) { @@ -106,6 +110,12 @@ public string GetImageProfileUrl(string path, string profileName, ContentItem co } } } + else { + // Since media with no ImagePart have no profile, filePath is null, so it's set again to its original path on the storage provider. + if (string.IsNullOrWhiteSpace(filePath)) { + filePath = _storageProvider.GetStoragePath(path); + } + } // todo: regenerate the file if the profile is newer, by deleting the associated filename cache entries. if (process) { @@ -115,13 +125,14 @@ public string GetImageProfileUrl(string path, string profileName, ContentItem co if (customFilters == null || !customFilters.Any(c => c != null)) { profilePart = _profileService.GetImageProfileByName(profileName); - if (profilePart == null) - return String.Empty; + if (profilePart == null) { + return string.Empty; + } } else { profilePart = _services.ContentManager.New("ImageProfile"); profilePart.Name = profileName; - foreach (var customFilter in customFilters) { + foreach (var customFilter in customFilters) { profilePart.Filters.Add(customFilter); } } @@ -129,15 +140,14 @@ public string GetImageProfileUrl(string path, string profileName, ContentItem co // prevent two requests from processing the same file at the same time // this is only thread safe at the machine level, so there is a try/catch later // to handle cross machines concurrency - lock (String.Intern(path)) { + lock (string.Intern(path)) { using (var image = GetImage(path)) { - - var filterContext = new FilterContext { Media = image, FilePath = _storageProvider.Combine("_Profiles", FormatProfilePath(profileName, System.Web.HttpUtility.UrlDecode(path))) }; - if (image == null) { - return filterContext.FilePath; + return null; } + var filterContext = new FilterContext { Media = image, FilePath = _storageProvider.Combine("_Profiles", FormatProfilePath(profileName, HttpUtility.UrlDecode(path))) }; + var tokens = new Dictionary(); // if a content item is provided, use it while tokenizing if (contentItem != null) { @@ -154,7 +164,7 @@ public string GetImageProfileUrl(string path, string profileName, ContentItem co descriptor.Filter(filterContext); } - _fileNameProvider.UpdateFileName(profileName, System.Web.HttpUtility.UrlDecode(path), filterContext.FilePath); + _fileNameProvider.UpdateFileName(profileName, HttpUtility.UrlDecode(path), filterContext.FilePath); if (!filterContext.Saved) { try { @@ -172,9 +182,11 @@ public string GetImageProfileUrl(string path, string profileName, ContentItem co } } } + // the storage provider may have altered the filepath + filterContext.FilePath = newFile.GetPath(); } } - catch(Exception e) { + catch (Exception e) { Logger.Error(e, "A profile could not be processed: " + path); } } @@ -203,14 +215,13 @@ private Stream GetImage(string path) { var file = _storageProvider.GetFile(storagePath); return file.OpenRead(); } - catch(Exception e) { + catch (Exception e) { Logger.Error(e, "path:" + path + " storagePath:" + storagePath); } } // http://blob.storage-provider.net/my-image.jpg - Uri absoluteUri; - if (Uri.TryCreate(path, UriKind.Absolute, out absoluteUri)) { + if (Uri.TryCreate(path, UriKind.Absolute, out Uri absoluteUri)) { return new WebClient().OpenRead(absoluteUri); } @@ -236,13 +247,12 @@ private bool TryGetImageLastUpdated(string path, out DateTime lastUpdated) { } private string FormatProfilePath(string profileName, string path) { - var filenameWithExtension = Path.GetFileName(path) ?? ""; var fileLocation = path.Substring(0, path.Length - filenameWithExtension.Length); return _storageProvider.Combine( - _storageProvider.Combine(profileName.GetHashCode().ToString("x").ToLowerInvariant(), fileLocation.GetHashCode().ToString("x").ToLowerInvariant()), - filenameWithExtension); + _storageProvider.Combine(_profileService.GetNameHashCode(profileName), _profileService.GetNameHashCode(fileLocation)), + filenameWithExtension); } } } diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileService.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileService.cs index 27e34228cdf..20853b6d376 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileService.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileService.cs @@ -1,31 +1,34 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Orchard.Caching; using Orchard.ContentManagement; using Orchard.Data; -using Orchard.Localization; +using Orchard.FileSystems.Media; +using Orchard.Logging; using Orchard.MediaProcessing.Models; namespace Orchard.MediaProcessing.Services { - public class ImageProfileService : IImageProfileService { + public class ImageProfileService : Component, IImageProfileService { private readonly IContentManager _contentManager; private readonly ICacheManager _cacheManager; private readonly IRepository _filterRepository; private readonly ISignals _signals; + private readonly IStorageProvider _storageProvider; public ImageProfileService( - IContentManager contentManager, + IContentManager contentManager, ICacheManager cacheManager, IRepository filterRepository, - ISignals signals) { + ISignals signals, + IStorageProvider storageProvider) { _contentManager = contentManager; _cacheManager = cacheManager; _filterRepository = filterRepository; _signals = signals; + _storageProvider = storageProvider; } - public Localizer T { get; set; } - public ImageProfilePart GetImageProfile(int id) { return _contentManager.Get(id); } @@ -70,6 +73,7 @@ public void DeleteImageProfile(int id) { var profile = _contentManager.Get(id); if (profile != null) { + DeleteImageProfileFolder(profile.As().Name); _contentManager.Remove(profile); } } @@ -115,5 +119,43 @@ public void MoveDown(int filterId) { next.Position = filter.Position; filter.Position = temp; } + + public bool PurgeImageProfile(int id) { + var profile = GetImageProfile(id); + try { + DeleteImageProfileFolder(profile.Name); + profile.FileNames.Clear(); + _signals.Trigger("MediaProcessing_Saved_" + profile.Name); + return true; + } + catch (Exception ex) { + Logger.Warning(ex, "Unable to purge image profile '{0}'", profile.Name); + return false; + } + } + + public bool PurgeObsoleteImageProfiles() { + var profiles = GetAllImageProfiles(); + try { + if (profiles != null) { + var validPaths = profiles.Select(profile => _storageProvider.Combine("_Profiles", this.GetNameHashCode(profile.Name))); + foreach (var folder in _storageProvider.ListFolders("_Profiles").Select(f => f.GetPath())) { + if (!validPaths.Any(folder.StartsWith)) { + _storageProvider.DeleteFolder(folder); + } + } + } + return true; + } + catch (Exception ex) { + Logger.Warning(ex, "Unable to purge obsolete image profiles"); + return false; + } + } + + private void DeleteImageProfileFolder(string profileName) { + var folder = _storageProvider.Combine("_Profiles", this.GetNameHashCode(profileName)); + _storageProvider.DeleteFolder(folder); + } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Shapes/MediaShapes.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Shapes/MediaShapes.cs index c2d640bce76..5f53191f756 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Shapes/MediaShapes.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Shapes/MediaShapes.cs @@ -22,13 +22,14 @@ public MediaShapes(Work imageProfileManager) { public ILogger Logger { get; set; } [Shape] - public void ResizeMediaUrl(dynamic Shape, dynamic Display, TextWriter Output, ContentItem ContentItem, string Path, int Width, int Height, string Mode, string Alignment, string PadColor) { + public void ResizeMediaUrl(dynamic Shape, dynamic Display, TextWriter Output, ContentItem ContentItem, string Path, int Width, int Height, string Mode, string Alignment, string PadColor, string Scale= "upscaleOnly") { var state = new Dictionary { {"Width", Width.ToString(CultureInfo.InvariantCulture)}, {"Height", Height.ToString(CultureInfo.InvariantCulture)}, {"Mode", Mode}, {"Alignment", Alignment}, {"PadColor", PadColor}, + {"Scale", Scale}, }; var filter = new FilterRecord { @@ -42,7 +43,8 @@ public void ResizeMediaUrl(dynamic Shape, dynamic Display, TextWriter Output, Co + "_h_" + Convert.ToString(Height) + "_m_" + Convert.ToString(Mode) + "_a_" + Convert.ToString(Alignment) - + "_c_" + Convert.ToString(PadColor); + + "_c_" + Convert.ToString(PadColor) + + "_s_" + Convert.ToString(Scale); MediaUrl(Shape, Display, Output, profile, Path, ContentItem, filter); } diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Views/Admin/Index.cshtml index bd6efd60a5d..c0b52fe1184 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Views/Admin/Index.cshtml @@ -14,7 +14,10 @@ @using (Html.BeginFormAntiForgeryPost()) { @Html.ValidationSummary() -
        @Html.ActionLink(T("Add a new Media Profile").ToString(), "Create", new { Area = "Contents", id = "ImageProfile", returnurl = HttpContext.Current.Request.RawUrl }, new { @class = "button primaryAction" })
        +
        + @Html.ActionLink(T("Purge Obsolete").ToString(), "PurgeObsolete", null, new { itemprop = "UnsafeUrl", @class = "button remove", data_unsafe_url = @T("Are you sure you wish to purge all obsolete profile images and force all dynamic profile images to be regenerated?").ToString() }) + @Html.ActionLink(T("Add a new Media Profile").ToString(), "Create", new { Area = "Contents", id = "ImageProfile", returnurl = HttpContext.Current.Request.RawUrl }, new { @class = "button primaryAction" }) +
        @@ -56,6 +59,7 @@ @Html.ActionLink(T("Properties").ToString(), "Edit", new { Area = "Contents", id = entry.ImageProfileId, returnurl = HttpContext.Current.Request.RawUrl }) | @Html.ActionLink(T("Edit").ToString(), "Edit", new { id = entry.ImageProfileId }) | + @Html.ActionLink(T("Purge").ToString(), "Purge", new { id = entry.ImageProfileId }, new { itemprop = "UnsafeUrl", data_unsafe_url = @T("Are you sure you wish to purge all images for this profile?").ToString() }) | @Html.ActionLink(T("Delete").ToString(), "Delete", new { id = entry.ImageProfileId }, new { itemprop = "RemoveUrl UnsafeUrl" }) @*@Html.ActionLink(T("Preview").ToString(), "Preview", new { id = entry.ImageProfileId })*@ diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Web.config b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Web.config index a3cb5df907e..baf3b31252b 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Web.config +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Web.config @@ -7,7 +7,7 @@ - + @@ -21,39 +21,58 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/packages.config b/src/Orchard.Web/Modules/Orchard.MediaProcessing/packages.config index 3572d0e4f9f..6fa6258dd4b 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/packages.config +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/packages.config @@ -1,8 +1,9 @@  - - - - - - \ No newline at end of file + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.MessageBus/Module.txt b/src/Orchard.Web/Modules/Orchard.MessageBus/Module.txt index 6d2e3701924..a935138c842 100644 --- a/src/Orchard.Web/Modules/Orchard.MessageBus/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.MessageBus/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Provides communication APIs for server farms. Features: Orchard.MessageBus: diff --git a/src/Orchard.Web/Modules/Orchard.MessageBus/Orchard.MessageBus.csproj b/src/Orchard.Web/Modules/Orchard.MessageBus/Orchard.MessageBus.csproj index 3c738d042cd..1a7796588a4 100644 --- a/src/Orchard.Web/Modules/Orchard.MessageBus/Orchard.MessageBus.csproj +++ b/src/Orchard.Web/Modules/Orchard.MessageBus/Orchard.MessageBus.csproj @@ -12,8 +12,8 @@ Properties Orchard.MessageBus Orchard.MessageBus - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -25,6 +25,7 @@ + true @@ -48,52 +49,54 @@ false - - ..\..\..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll - True + + ..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll + + + ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - - ..\..\..\packages\NHibernate.4.0.1.4000\lib\net40\NHibernate.dll - True + + ..\..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll + + + ..\..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll + + + ..\..\..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll 3.5 + + - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -110,12 +113,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) @@ -135,7 +138,7 @@ - + 10.0 @@ -161,7 +164,7 @@ --> - + @@ -175,10 +178,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.MessageBus/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.MessageBus/Properties/AssemblyInfo.cs index e6a05a8b29f..356789001f9 100644 --- a/src/Orchard.Web/Modules/Orchard.MessageBus/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.MessageBus/Properties/AssemblyInfo.cs @@ -32,6 +32,6 @@ // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.MessageBus/Web.config b/src/Orchard.Web/Modules/Orchard.MessageBus/Web.config index 314606a772b..1fc8f61a052 100644 --- a/src/Orchard.Web/Modules/Orchard.MessageBus/Web.config +++ b/src/Orchard.Web/Modules/Orchard.MessageBus/Web.config @@ -7,7 +7,7 @@ - + @@ -22,36 +22,47 @@ - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.MessageBus/packages.config b/src/Orchard.Web/Modules/Orchard.MessageBus/packages.config index 96e09a98934..249ae771231 100644 --- a/src/Orchard.Web/Modules/Orchard.MessageBus/packages.config +++ b/src/Orchard.Web/Modules/Orchard.MessageBus/packages.config @@ -1,9 +1,12 @@  - - - - - - - \ No newline at end of file + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Migrations/Module.txt b/src/Orchard.Web/Modules/Orchard.Migrations/Module.txt index c7bd03f88dd..bc8b00e3678 100644 --- a/src/Orchard.Web/Modules/Orchard.Migrations/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Migrations/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Data migration commands. FeatureDescription: Data migration commands. Category: Developer diff --git a/src/Orchard.Web/Modules/Orchard.Migrations/Orchard.Migrations.csproj b/src/Orchard.Web/Modules/Orchard.Migrations/Orchard.Migrations.csproj index fed304b8102..27fe5c561cf 100644 --- a/src/Orchard.Web/Modules/Orchard.Migrations/Orchard.Migrations.csproj +++ b/src/Orchard.Web/Modules/Orchard.Migrations/Orchard.Migrations.csproj @@ -13,8 +13,8 @@ Properties Orchard.Migrations Orchard.Migrations - v4.5.2 - false + v4.8 + 7.3 @@ -27,6 +27,7 @@ + true @@ -52,7 +53,6 @@ ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -62,28 +62,22 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -102,16 +96,16 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) - + 10.0 @@ -139,10 +133,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Migrations/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Migrations/Properties/AssemblyInfo.cs index 55087798ae6..8f534edcd06 100644 --- a/src/Orchard.Web/Modules/Orchard.Migrations/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Migrations/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Migrations/Web.config b/src/Orchard.Web/Modules/Orchard.Migrations/Web.config index 314606a772b..1fc8f61a052 100644 --- a/src/Orchard.Web/Modules/Orchard.Migrations/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Migrations/Web.config @@ -7,7 +7,7 @@ - + @@ -22,36 +22,47 @@ - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Migrations/packages.config b/src/Orchard.Web/Modules/Orchard.Migrations/packages.config index 6729ced4977..84f4c1e1392 100644 --- a/src/Orchard.Web/Modules/Orchard.Migrations/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Migrations/packages.config @@ -1,7 +1,7 @@  - - - - - \ No newline at end of file + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Modules/AdminMenu.cs b/src/Orchard.Web/Modules/Orchard.Modules/AdminMenu.cs index 79b3f193c5c..aea0dd55977 100644 --- a/src/Orchard.Web/Modules/Orchard.Modules/AdminMenu.cs +++ b/src/Orchard.Web/Modules/Orchard.Modules/AdminMenu.cs @@ -15,7 +15,6 @@ public void GetNavigation(NavigationBuilder builder) { .Add(T("Modules"), "9", menu => menu.Action("Features", "Admin", new {area = "Orchard.Modules"}).Permission(Permissions.ManageFeatures) .Add(T("Features"), "0", item => item.Action("Features", "Admin", new {area = "Orchard.Modules"}).Permission(Permissions.ManageFeatures).LocalNav()) .Add(T("Installed"), "1", item => item.Action("Index", "Admin", new { area = "Orchard.Modules" }).Permission(StandardPermissions.SiteOwner).LocalNav()) - .Add(T("Recipes"), "2", item => item.Action("Recipes", "Admin", new { area = "Orchard.Modules" }).Permission(StandardPermissions.SiteOwner).LocalNav()) ); } } diff --git a/src/Orchard.Web/Modules/Orchard.Modules/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Modules/Controllers/AdminController.cs index 3f7247cdf45..44e69f2a6a3 100644 --- a/src/Orchard.Web/Modules/Orchard.Modules/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Modules/Controllers/AdminController.cs @@ -17,8 +17,6 @@ using Orchard.Modules.ViewModels; using Orchard.Mvc; using Orchard.Mvc.Extensions; -using Orchard.Recipes.Models; -using Orchard.Recipes.Services; using Orchard.Security; using Orchard.UI.Navigation; using Orchard.UI.Notify; @@ -30,8 +28,6 @@ public class AdminController : Controller { private readonly IDataMigrationManager _dataMigrationManager; private readonly IExtensionManager _extensionManager; private readonly IFeatureManager _featureManager; - private readonly IRecipeHarvester _recipeHarvester; - private readonly IRecipeManager _recipeManager; private readonly ShellDescriptor _shellDescriptor; private readonly ShellSettings _shellSettings; @@ -42,8 +38,6 @@ public AdminController( IDataMigrationManager dataMigrationManager, IExtensionManager extensionManager, IFeatureManager featureManager, - IRecipeHarvester recipeHarvester, - IRecipeManager recipeManager, ShellDescriptor shellDescriptor, ShellSettings shellSettings, IShapeFactory shapeFactory) { @@ -53,8 +47,6 @@ public AdminController( _dataMigrationManager = dataMigrationManager; _extensionManager = extensionManager; _featureManager = featureManager; - _recipeHarvester = recipeHarvester; - _recipeManager = recipeManager; _shellDescriptor = shellDescriptor; _shellSettings = shellSettings; Shape = shapeFactory; @@ -111,62 +103,6 @@ public ActionResult Index(ModulesIndexOptions options, PagerParameters pagerPara }); } - public ActionResult Recipes() { - if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not allowed to manage modules"))) - return new HttpUnauthorizedResult(); - - IEnumerable modules = _extensionManager.AvailableExtensions() - .Where(extensionDescriptor => ExtensionIsAllowed(extensionDescriptor)) - .OrderBy(extensionDescriptor => extensionDescriptor.Name) - .Select(extensionDescriptor => new ModuleEntry { Descriptor = extensionDescriptor }); - - var viewModel = new RecipesViewModel(); - - if (_recipeHarvester != null) { - viewModel.Modules = modules.Select(x => new ModuleRecipesViewModel { - Module = x, - Recipes = _recipeHarvester.HarvestRecipes(x.Descriptor.Id).Where(recipe => !recipe.IsSetupRecipe).ToList() - }) - .Where(x => x.Recipes.Any()) - .ToList(); - } - - return View(viewModel); - - } - - [HttpPost, ActionName("Recipes")] - public ActionResult RecipesPOST(string moduleId, string name) { - if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not allowed to manage modules"))) - return new HttpUnauthorizedResult(); - - ModuleEntry module = _extensionManager.AvailableExtensions() - .Where(extensionDescriptor => extensionDescriptor.Id == moduleId && ExtensionIsAllowed(extensionDescriptor)) - .Select(extensionDescriptor => new ModuleEntry { Descriptor = extensionDescriptor }).FirstOrDefault(); - - if (module == null) { - return HttpNotFound(); - } - - Recipe recipe = _recipeHarvester.HarvestRecipes(module.Descriptor.Id).FirstOrDefault(x => !x.IsSetupRecipe && x.Name == name); - - if (recipe == null) { - return HttpNotFound(); - } - - try { - _recipeManager.Execute(recipe); - } - catch (Exception e) { - Logger.Error(e, "Error while executing recipe {0} in {1}", moduleId, name); - Services.Notifier.Error(T("Recipes {0} contains unsupported module installation steps.", recipe.Name)); - } - - Services.Notifier.Success(T("The recipe {0} was executed successfully.", recipe.Name)); - - return RedirectToAction("Recipes"); - - } public ActionResult Features() { if (!Services.Authorizer.Authorize(Permissions.ManageFeatures, T("Not allowed to manage features"))) return new HttpUnauthorizedResult(); diff --git a/src/Orchard.Web/Modules/Orchard.Modules/Module.txt b/src/Orchard.Web/Modules/Orchard.Modules/Module.txt index 9b55fe8bb54..c9583221b0a 100644 --- a/src/Orchard.Web/Modules/Orchard.Modules/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Modules/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: The Modules module enables the administrator of the site to manage the installed modules as well as activate and de-activate features. FeatureDescription: Standard module and feature management. Category: Core diff --git a/src/Orchard.Web/Modules/Orchard.Modules/Orchard.Modules.csproj b/src/Orchard.Web/Modules/Orchard.Modules/Orchard.Modules.csproj index fd458c51b6f..37568145237 100644 --- a/src/Orchard.Web/Modules/Orchard.Modules/Orchard.Modules.csproj +++ b/src/Orchard.Web/Modules/Orchard.Modules/Orchard.Modules.csproj @@ -12,8 +12,8 @@ Properties Orchard.Modules Orchard.Modules - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,9 @@ + + + true @@ -51,12 +54,13 @@ ..\..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll - True + + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -66,28 +70,22 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -107,7 +105,6 @@ - @@ -129,7 +126,7 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) @@ -154,9 +151,6 @@ - - - @@ -169,7 +163,7 @@ - + 10.0 @@ -197,10 +191,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Modules/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Modules/Properties/AssemblyInfo.cs index 97187fa598b..ec2f3fb918e 100644 --- a/src/Orchard.Web/Modules/Orchard.Modules/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Modules/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Modules/Views/Admin/Features.cshtml b/src/Orchard.Web/Modules/Orchard.Modules/Views/Admin/Features.cshtml index 54760cb2c37..3e4740b9b44 100644 --- a/src/Orchard.Web/Modules/Orchard.Modules/Views/Admin/Features.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Modules/Views/Admin/Features.cshtml @@ -71,7 +71,7 @@ continue; } //hmmm...I feel like I've done this before... - var lifecycleStatus = feature.Descriptor.Extension.LifecycleStatus; + var lifecycleStatus = feature.Descriptor.LifecycleStatus; var featureId = feature.Descriptor.Id.AsFeatureId(n => T(n)); var featureName = string.IsNullOrEmpty(feature.Descriptor.Name) ? feature.Descriptor.Id : feature.Descriptor.Name; var featureState = feature.IsEnabled ? "enabled" : "disabled"; @@ -91,7 +91,8 @@ select (from f in Model.Features where f.Descriptor.Id.Equals(d, StringComparison.OrdinalIgnoreCase) select f).SingleOrDefault()).Where(f => f != null).OrderBy(f => f.Descriptor.Name); var missingDependencies = feature.Descriptor.Dependencies .Where(d => !Model.Features.Any(f => f.Descriptor.Id.Equals(d, StringComparison.OrdinalIgnoreCase))); - var showDisable = categoryName.ToString() != "Core"; + var showDisable = categoryName.ToString() != "Core" + || lifecycleStatus == LifecycleStatus.Deprecated; // we should always be able to disable deprecated features even if they are categorized as "Core" var showEnable = Model.IsAllowed(feature.Descriptor.Extension) && !missingDependencies.Any() && feature.Descriptor.Id != "Orchard.Setup"; if (missingDependencies.Any()) { diff --git a/src/Orchard.Web/Modules/Orchard.Modules/Views/Admin/Recipes.cshtml b/src/Orchard.Web/Modules/Orchard.Modules/Views/Admin/Recipes.cshtml deleted file mode 100644 index 17f9d04ddd5..00000000000 --- a/src/Orchard.Web/Modules/Orchard.Modules/Views/Admin/Recipes.cshtml +++ /dev/null @@ -1,39 +0,0 @@ -@using Orchard.Utility.Extensions -@model Orchard.Modules.ViewModels.RecipesViewModel - -@{ - Layout.Title = T("Recipes"); -} -@using (Html.BeginFormAntiForgeryPost()) { - if (Model.Modules.Any()) { -
          - @foreach (var moduleEntry in Model.Modules.OrderBy(m => m.Module.Descriptor.Name)) { - var module = moduleEntry.Module; - var descriptor = module.Descriptor; - -
        • -
          -
          -

          @descriptor.Name - @T("Version: {0}", !string.IsNullOrEmpty(descriptor.Version) ? descriptor.Version : T("1.0").ToString())

          - - @*@if (!string.IsNullOrEmpty(descriptor.Description)) { -

          @descriptor.Description

          - }*@ - - @foreach (var recipe in moduleEntry.Recipes) { -
          -
          -

          @recipe.Name.CamelFriendly() - @Html.ActionLink(T("Execute").Text, "Recipes", "Admin", new { area = "Orchard.Modules", moduleId = descriptor.Id, name = recipe.Name }, new { itemprop = "UnsafeUrl" })

          -

          @(!string.IsNullOrEmpty(recipe.Description) ? recipe.Description : T("No description").ToString())

          -
          - } -
          -
          -
        • - } -
        - } - else { -

        @T("No modules available").ToString()

        - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Modules/Views/ModuleEntry.cshtml b/src/Orchard.Web/Modules/Orchard.Modules/Views/ModuleEntry.cshtml index fa469f72228..3e9e31bcdb7 100644 --- a/src/Orchard.Web/Modules/Orchard.Modules/Views/ModuleEntry.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Modules/Views/ModuleEntry.cshtml @@ -28,7 +28,7 @@ T("Uninstall").Text, "UninstallModule", "PackagingServices", - new { ModuleId = module.Descriptor.Id, ReturnUrl = Request.ToUrlString(), Area = "Orchard.Packaging" }, + new { ModuleId = module.Descriptor.Id, ReturnUrl = Request.RawUrl, Area = "Orchard.Packaging" }, new { itemprop = "RemoveUrl UnsafeUrl" }) @if (!String.IsNullOrEmpty(module.Descriptor.Description)) { diff --git a/src/Orchard.Web/Modules/Orchard.Modules/Web.config b/src/Orchard.Web/Modules/Orchard.Modules/Web.config index a3cb5df907e..c5ae93f4f3c 100644 --- a/src/Orchard.Web/Modules/Orchard.Modules/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Modules/Web.config @@ -7,7 +7,7 @@ - + @@ -21,39 +21,57 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Modules/packages.config b/src/Orchard.Web/Modules/Orchard.Modules/packages.config index 7f7f2ffd4f1..1e7018b24a2 100644 --- a/src/Orchard.Web/Modules/Orchard.Modules/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Modules/packages.config @@ -1,8 +1,9 @@  - - - - - - \ No newline at end of file + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Controllers/AdminController.cs index 9b7ce5a6597..6ae55dfcfba 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Controllers/AdminController.cs @@ -70,6 +70,10 @@ public ActionResult AddPost(TenantAddViewModel viewModel) { ModelState.AddModelError("Name", T("Invalid tenant name. Must contain characters only and no spaces.").Text); } + if (string.Equals(viewModel.Name, ShellSettingsSerializer.EmptyValue, StringComparison.OrdinalIgnoreCase)) { + ModelState.AddModelError("Name", T("Invalid tenant name.").Text); + } + if (!string.Equals(viewModel.Name, "default", StringComparison.OrdinalIgnoreCase) && string.IsNullOrWhiteSpace( viewModel.RequestUrlHost) && string.IsNullOrWhiteSpace(viewModel.RequestUrlPrefix)) { ModelState.AddModelError("RequestUrlHostRequestUrlPrefix", T("RequestUrlHost and RequestUrlPrefix can not be empty at the same time.").Text); } diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Module.txt b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Module.txt index 93115279131..e0d06d92c2f 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Module.txt @@ -3,8 +3,8 @@ Path: MultiTenancy AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: The multi-tenancy module enables multiple Orchard sites to run in isolation inside of a single web application, improving site density on a single server or hosted account. FeatureDescription: Configure multiple site tenants. Category: Hosting diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Orchard.MultiTenancy.csproj b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Orchard.MultiTenancy.csproj index 80bfe4304c5..5f92927b8d2 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Orchard.MultiTenancy.csproj +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Orchard.MultiTenancy.csproj @@ -12,8 +12,8 @@ Properties Orchard.MultiTenancy Orchard.MultiTenancy - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,9 @@ + + +
        true @@ -49,56 +52,62 @@ false + + ..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll + ..\..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll - True - - ..\..\..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll - True + + ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll + + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - - ..\..\..\packages\NHibernate.4.0.1.4000\lib\net40\NHibernate.dll - True + + ..\..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll + + + ..\..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll + + + ..\..\..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll 3.5 + + + - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -139,7 +148,7 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - False + $(MvcBuildViews) @@ -166,7 +175,7 @@ - + 10.0 @@ -194,7 +203,7 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Properties/AssemblyInfo.cs index f22e644f34d..f7e7305cd6f 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Routes.cs b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Routes.cs index abdc9975fe5..04508d9958b 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Routes.cs +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Routes.cs @@ -5,10 +5,9 @@ namespace Orchard.MultiTenancy { public class Routes : IRouteProvider { - public IEnumerable GetRoutes() { - return new[] { - new RouteDescriptor { - Route = new Route( + public void GetRoutes(ICollection routes) { + var routeDescriptor = new RouteDescriptor { + Route = new Route( "Admin/MultiTenancy/Edit/{name}", new RouteValueDictionary { {"area", "Orchard.MultiTenancy"}, @@ -22,14 +21,9 @@ public IEnumerable GetRoutes() { {"area", "Orchard.MultiTenancy"} }, new MvcRouteHandler()) - } - }; - } + }; - public void GetRoutes(ICollection routes) { - foreach (RouteDescriptor routeDescriptor in GetRoutes()) { - routes.Add(routeDescriptor); - } + routes.Add(routeDescriptor); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/TenantService.cs b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/TenantService.cs index 4eb7c26da2e..60edac9086f 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/TenantService.cs +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/TenantService.cs @@ -7,6 +7,7 @@ using Orchard.Environment.ShellBuilders; using Orchard.Data.Migration.Interpreters; using Orchard.Data.Migration.Schema; +using Orchard.Data.Providers; using Orchard.Data; using Orchard.Logging; @@ -104,14 +105,37 @@ private void ExecuteOnTenantScope(ShellSettings settings, Action GetTenantDatabaseTableNames(IWorkContextScope environment) { - var sessionFactoryHolder = environment.Resolve(); - var configuration = sessionFactoryHolder.GetConfiguration(); + var shellSettings = environment.Resolve(); + var sqlStatementProviders = environment.Resolve>(); + var transactionManager = environment.Resolve(); + var session = transactionManager.GetSession(); + var tenants = GetTenants().Where(x => x.Name != shellSettings.Name); - var result = - from mapping in configuration.ClassMappings - select mapping.Table.Name; + string command = null; + IEnumerable result = null; + + foreach (var sqlStatementProvider in sqlStatementProviders) { + if (!String.Equals(sqlStatementProvider.DataProvider, shellSettings.DataProvider)) { + continue; + } + + command = sqlStatementProvider.GetStatement("table_names") ?? command; + } + + if (command != null) { + var tableNames = session.CreateSQLQuery(command).List(); + + if (string.IsNullOrWhiteSpace(shellSettings.DataTablePrefix)) { + // If current tenant doesn't has table prefix, then exclude all tables which have prefixes for other tenants + result = tableNames.Where(table => !tenants.Any(tenant => table.StartsWith(tenant.DataTablePrefix + "_"))); + } + else { + // If current tenant has table prefix, then filter tables which have the right prefix + result = tableNames.Where(table => table.StartsWith(shellSettings.DataTablePrefix + "_")); + } + } - return result.ToArray(); + return (result ?? Enumerable.Empty()).OrderBy(x => x).ToList(); } private void DropTenantDatabaseTables(IWorkContextScope environment) { diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/DisplayTemplates/ActionsForDisabled.cshtml b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/DisplayTemplates/ActionsForDisabled.cshtml index a261fbacfba..0e6c464a290 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/DisplayTemplates/ActionsForDisabled.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/DisplayTemplates/ActionsForDisabled.cshtml @@ -1,8 +1,13 @@ @model Orchard.Environment.Configuration.ShellSettings -@using Orchard.MultiTenancy.Extensions; -@using(Html.BeginFormAntiForgeryPost(Url.Action("Enable", new {area = "Orchard.MultiTenancy"}), FormMethod.Post, new {@class = "inline link"})) { - @Html.HiddenFor(ss => ss.Name) - -} @T(" | ") -@Html.ActionLink(T("Reset").ToString(), "Reset", new { name = Model.Name, area = "Orchard.MultiTenancy" }) \ No newline at end of file + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/Index.cshtml index af1334474cc..32e504effde 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/Index.cshtml @@ -13,8 +13,9 @@
      • -

        @tenant.Name - @if (!String.IsNullOrEmpty(tenant.RequestUrlHost)) { +

        + @tenant.Name + @if (!String.IsNullOrEmpty(tenant.RequestUrlHost)) { var tenantClone = new ShellSettings(tenant); foreach (var t in tenant.RequestUrlHost.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { tenantClone.RequestUrlHost = t; @@ -25,11 +26,17 @@

      • diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Web.config b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Web.config index a3cb5df907e..c5ae93f4f3c 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Web.config +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Web.config @@ -7,7 +7,7 @@ - + @@ -21,39 +21,57 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/packages.config b/src/Orchard.Web/Modules/Orchard.MultiTenancy/packages.config index 7e41029be62..5b9210e80cc 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/packages.config +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/packages.config @@ -1,10 +1,14 @@  - - - - - - - - \ No newline at end of file + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Constants/General.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Constants/General.cs index 15dd6f6b8e1..49253e24384 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Constants/General.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Constants/General.cs @@ -1,7 +1,7 @@ namespace Orchard.OpenId.Constants { public class General { - public const string AuthenticationErrorUrl = "~/Authentication/Error"; - public const string LogonCallbackUrl = "~/Users/Account/LogonCallback"; + public const string AuthenticationErrorUrl = "/Authentication/Error"; + public const string LogonCallbackUrl = "/Users/Account/LogonCallback"; public const string OpenIdOwinMiddlewarePriority = "10"; public const string LocalIssuer = "LOCAL AUTHORITY"; public const string FormsIssuer = "Forms"; diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Controllers/AccountController.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Controllers/AccountController.cs index bdf7a72bd69..aace6eae149 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Controllers/AccountController.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Controllers/AccountController.cs @@ -6,6 +6,7 @@ using Microsoft.Owin.Security; using Microsoft.Owin.Security.Cookies; using Microsoft.Owin.Security.OpenIdConnect; +using Orchard.Environment.Configuration; using Orchard.Environment.Extensions; using Orchard.Localization; using Orchard.Logging; @@ -18,6 +19,7 @@ namespace Orchard.OpenId.Controllers { [Themed] + [AlwaysAccessible] [OrchardFeature("Orchard.OpenId")] public class AccountController : Controller { private readonly IEnumerable _openIdProviders; @@ -48,16 +50,17 @@ public AccountController( [AlwaysAccessible] [HttpGet] - public ActionResult LogOn() { + public ActionResult LogOn(string returnUrl) { if (Request.IsAuthenticated) { - return Redirect(Url.Content("~/")); + return Redirect("~/"); } + ViewData["ReturnUrl"] = returnUrl; + return View(_openIdProviders); } [HttpPost] - [AlwaysAccessible] [ValidateInput(false)] [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", Justification = "Needs to take same parameter type as Controller.Redirect()")] public ActionResult LogOn(string userNameOrEmail, string password, string returnUrl, bool rememberMe = false) { @@ -83,23 +86,28 @@ public ActionResult LogOn(string userNameOrEmail, string password, string return return this.RedirectLocal(returnUrl); } - public void Challenge(string openIdProvider) { + [AlwaysAccessible] + [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", Justification = "Needs to take same parameter type as Controller.Redirect()")] + public void Challenge(string openIdProvider, string returnUrl) { _userEventHandler.LoggingIn(openIdProvider, String.Empty); if (String.IsNullOrWhiteSpace(openIdProvider)) openIdProvider = OpenIdConnectAuthenticationDefaults.AuthenticationType; if (Request.IsAuthenticated) { - Redirect(Url.Content("~/")); + this.RedirectLocal(returnUrl); return; } + else { + TempData["ReturnUrl"] = returnUrl; + } - var redirectUri = Url.Content(String.Concat(Constants.General.LogonCallbackUrl)); + var redirectUri = Url.Content(GetCallbackPath(_orchardServices.WorkContext)); HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = redirectUri }, openIdProvider); } - public RedirectResult LogOff(string openIdProvider) { + public ActionResult LogOff(string openIdProvider) { if (String.IsNullOrWhiteSpace(openIdProvider)) openIdProvider = OpenIdConnectAuthenticationDefaults.AuthenticationType; @@ -111,14 +119,20 @@ public RedirectResult LogOff(string openIdProvider) { _userEventHandler.LoggedOut(loggedUser); } - return Redirect(Url.Content("~/")); + return Redirect("~/"); } - public RedirectResult LogonCallback() { + public ActionResult LogonCallback() { var user = _authenticationService.GetAuthenticatedUser(); - _userEventHandler.LoggedIn(user); - return Redirect(Url.Content("~/")); + if (user != null) { + _userEventHandler.LoggedIn(user); + } + + if (TempData.ContainsKey("ReturnUrl")) + return this.RedirectLocal((String)TempData["ReturnUrl"]); + else + return Redirect("~/"); } public ActionResult AccessDenied() { @@ -126,7 +140,7 @@ public ActionResult AccessDenied() { var currentUser = _authenticationService.GetAuthenticatedUser(); if (currentUser == null) { - return RedirectToAction("Logon"); + return RedirectToAction("Logon", new { returnUrl = returnUrl }); } _userEventHandler.AccessDenied(currentUser); @@ -153,12 +167,25 @@ private IUser ValidateLogOn(string userNameOrEmail, string password) { if (!validate) return null; - var user = _membershipService.ValidateUser(userNameOrEmail, password); + List validationErrors; + var user = _membershipService.ValidateUser(userNameOrEmail, password, out validationErrors); if (user == null) { ModelState.AddModelError("password", T("The username or e-mail or password provided is incorrect.")); } return user; } + + private string GetCallbackPath(WorkContext workContext) + { + var shellSettings = workContext.Resolve(); + var tenantPrefix = shellSettings.RequestUrlPrefix; + + var callbackUrl = string.IsNullOrWhiteSpace(tenantPrefix) ? + Constants.General.LogonCallbackUrl : + string.Format("/{0}{1}", tenantPrefix, Constants.General.LogonCallbackUrl); + + return callbackUrl; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Models/ActiveDirectoryFederationServicesSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Models/ActiveDirectoryFederationServicesSettingsPart.cs index 9897ed049cd..c126fd24fda 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Models/ActiveDirectoryFederationServicesSettingsPart.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Models/ActiveDirectoryFederationServicesSettingsPart.cs @@ -21,19 +21,17 @@ public string PostLogoutRedirectUri { set { this.Store(x => x.PostLogoutRedirectUri, value); } } - public bool IsValid { - get { - if (String.IsNullOrWhiteSpace(ClientId) || - String.CompareOrdinal(ClientId, Constants.ActiveDirectoryFederationServices.DefaultClientId) == 0 || - String.IsNullOrWhiteSpace(MetadataAddress) || - String.CompareOrdinal(MetadataAddress, Constants.ActiveDirectoryFederationServices.DefaultMetadataAddress) == 0 || - String.IsNullOrWhiteSpace(PostLogoutRedirectUri)) { + public bool IsValid() { + if (String.IsNullOrWhiteSpace(ClientId) || + String.CompareOrdinal(ClientId, Constants.ActiveDirectoryFederationServices.DefaultClientId) == 0 || + String.IsNullOrWhiteSpace(MetadataAddress) || + String.CompareOrdinal(MetadataAddress, Constants.ActiveDirectoryFederationServices.DefaultMetadataAddress) == 0 || + String.IsNullOrWhiteSpace(PostLogoutRedirectUri)) { - return false; - } - - return true; + return false; } + + return true; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Models/AzureActiveDirectorySettingsPart.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Models/AzureActiveDirectorySettingsPart.cs index e332bb554f9..fedd22e3801 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Models/AzureActiveDirectorySettingsPart.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Models/AzureActiveDirectorySettingsPart.cs @@ -71,19 +71,22 @@ public string AppKey { set { this.Store(x => x.AppKey, value); } } - public bool IsValid { - get { - if (String.IsNullOrWhiteSpace(Tenant) || - String.IsNullOrWhiteSpace(ClientId) || - String.IsNullOrWhiteSpace(LogoutRedirectUri) || - String.IsNullOrWhiteSpace(ServiceResourceID) || - String.IsNullOrWhiteSpace(AppKey)) { + public string GraphApiKey { + get { return this.Retrieve(x => x.GraphApiKey); } + set { this.Store(x => x.GraphApiKey, value); } + } - return false; - } + public bool IsValid() { + if (String.IsNullOrWhiteSpace(Tenant) || + String.IsNullOrWhiteSpace(ClientId) || + String.IsNullOrWhiteSpace(LogoutRedirectUri) || + String.IsNullOrWhiteSpace(ServiceResourceID) || + String.IsNullOrWhiteSpace(AppKey)) { - return true; + return false; } + + return true; } public Dictionary ServiceResourceIDs { diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Models/FacebookSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Models/FacebookSettingsPart.cs index f4f84b1555e..3da96540401 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Models/FacebookSettingsPart.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Models/FacebookSettingsPart.cs @@ -16,18 +16,16 @@ public string AppSecret { set { this.Store(x => x.AppSecret, value); } } - public bool IsValid { - get { - if (String.IsNullOrWhiteSpace(AppId) || - String.CompareOrdinal(AppId, Constants.Facebook.DefaultAppId) == 0 || - String.IsNullOrWhiteSpace(AppSecret) || - String.CompareOrdinal(AppSecret, Constants.Facebook.DefaultAppSecret) == 0) { + public bool IsValid() { + if (String.IsNullOrWhiteSpace(AppId) || + String.CompareOrdinal(AppId, Constants.Facebook.DefaultAppId) == 0 || + String.IsNullOrWhiteSpace(AppSecret) || + String.CompareOrdinal(AppSecret, Constants.Facebook.DefaultAppSecret) == 0) { - return false; - } - - return true; + return false; } + + return true; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Models/GoogleSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Models/GoogleSettingsPart.cs index 08656e223f0..a34cdc61fd8 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Models/GoogleSettingsPart.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Models/GoogleSettingsPart.cs @@ -1,8 +1,10 @@ using System; +using System.ComponentModel.DataAnnotations; using Orchard.ContentManagement; using Orchard.Environment.Extensions; -namespace Orchard.OpenId.Models { +namespace Orchard.OpenId.Models +{ [OrchardFeature("Orchard.OpenId.Google")] public class GoogleSettingsPart : ContentPart { @@ -16,24 +18,25 @@ public string ClientSecret { set { this.Store(x => x.ClientSecret, value); } } + [RegularExpression(pattern: "/.+", ErrorMessage = "The Callback Path Must start with a forward slash '/' followed by one or more characters")] public string CallbackPath { get { return this.Retrieve(x => x.CallbackPath, () => Constants.General.LogonCallbackUrl); } set { this.Store(x => x.CallbackPath, value); } } - public bool IsValid { - get { - if (String.IsNullOrWhiteSpace(ClientId) || - String.CompareOrdinal(ClientId, Constants.Google.DefaultClientId) == 0 || - String.IsNullOrWhiteSpace(ClientSecret) || - String.CompareOrdinal(ClientId, Constants.Google.DefaultClientSecret) == 0 || - String.IsNullOrWhiteSpace(CallbackPath)) { + public bool IsValid() { + if (String.IsNullOrWhiteSpace(ClientId) || + String.CompareOrdinal(ClientId, Constants.Google.DefaultClientId) == 0 || + String.IsNullOrWhiteSpace(ClientSecret) || + String.CompareOrdinal(ClientId, Constants.Google.DefaultClientSecret) == 0 || + String.IsNullOrWhiteSpace(CallbackPath) || + CallbackPath.StartsWith("/") == false || + CallbackPath.Length < 2) { - return false; - } - - return true; + return false; } + + return true; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Models/TwitterSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Models/TwitterSettingsPart.cs index d15b45639f7..8c494cb34ea 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Models/TwitterSettingsPart.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Models/TwitterSettingsPart.cs @@ -16,18 +16,16 @@ public string ConsumerSecret { set { this.Store(x => x.ConsumerSecret, value); } } - public bool IsValid { - get { - if (String.IsNullOrWhiteSpace(ConsumerKey) || - String.CompareOrdinal(ConsumerKey, Constants.Twitter.DefaultConsumerKey) == 0 || - String.IsNullOrWhiteSpace(ConsumerSecret) || - String.CompareOrdinal(ConsumerSecret, Constants.Twitter.DefaultConsumerSecret) == 0) { + public bool IsValid() { + if (String.IsNullOrWhiteSpace(ConsumerKey) || + String.CompareOrdinal(ConsumerKey, Constants.Twitter.DefaultConsumerKey) == 0 || + String.IsNullOrWhiteSpace(ConsumerSecret) || + String.CompareOrdinal(ConsumerSecret, Constants.Twitter.DefaultConsumerSecret) == 0) { - return false; - } - - return true; + return false; } + + return true; } public string VeriSignClass3SecureServerCA_G2 diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Module.txt b/src/Orchard.Web/Modules/Orchard.OpenId/Module.txt index f137e25624e..d57b9ac6a11 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Module.txt @@ -11,6 +11,7 @@ Features: Description: Enables Orchard to authenticate users using OpenId Category: Authentication Name: OpenId + Dependencies: Orchard.Users Orchard.OpenId.Facebook: Description: Enables Orchard to authenticate users using their Facebook Accounts Category: Authentication @@ -25,7 +26,7 @@ Features: Description: Enables Orchard to authenticate users using their Twitter Accounts Category: Authentication Name: Twitter - Dependencies: Orchard.OpenId + Dependencies: Orchard.OpenId, Orchard.Resources Orchard.OpenId.AzureActiveDirectory: Description: Enables Orchard to authenticate users using their Azure AD Accounts Category: Authentication diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Orchard.OpenId.csproj b/src/Orchard.Web/Modules/Orchard.OpenId/Orchard.OpenId.csproj index 7971ec25e6e..5eb6ee7f5fa 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Orchard.OpenId.csproj +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Orchard.OpenId.csproj @@ -12,8 +12,8 @@ Properties Orchard.OpenId Orchard.OpenId - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -25,6 +25,7 @@ +
        true @@ -48,99 +49,121 @@ false - - ..\..\..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll - True + + ..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll + + + ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll + + + ..\..\..\packages\log4net.2.0.12\lib\net45\log4net.dll ..\..\..\packages\Microsoft.Azure.ActiveDirectory.GraphClient.2.1.1\lib\portable-net4+sl5+win+wpa+wp8\Microsoft.Azure.ActiveDirectory.GraphClient.dll True + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + - - ..\..\..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll + + ..\..\..\packages\Microsoft.Data.Edm.5.8.4\lib\net40\Microsoft.Data.Edm.dll True - - ..\..\..\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll + + ..\..\..\packages\Microsoft.Data.OData.5.8.4\lib\net40\Microsoft.Data.OData.dll True - - ..\..\..\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll + + ..\..\..\packages\Microsoft.Data.Services.Client.5.8.4\lib\net40\Microsoft.Data.Services.Client.dll True - - ..\..\..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.13.5\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll - True + + ..\..\..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll - - ..\..\..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.13.5\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll - True + + ..\..\..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll - - ..\..\..\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.2.206221351\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll - True + + ..\..\..\packages\Microsoft.IdentityModel.JsonWebTokens.5.7.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.dll - - ..\..\..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll - True + + ..\..\..\packages\Microsoft.IdentityModel.Logging.5.7.0\lib\net461\Microsoft.IdentityModel.Logging.dll - - ..\..\..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll - True + + ..\..\..\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.4.403061554\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll - - ..\..\..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll - True + + ..\..\..\packages\Microsoft.IdentityModel.Protocols.5.7.0\lib\net461\Microsoft.IdentityModel.Protocols.dll - - ..\..\..\packages\Microsoft.Owin.Security.ActiveDirectory.3.0.1\lib\net45\Microsoft.Owin.Security.ActiveDirectory.dll - True + + ..\..\..\packages\Microsoft.IdentityModel.Protocols.OpenIdConnect.5.7.0\lib\net461\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll - - ..\..\..\packages\Microsoft.Owin.Security.Cookies.3.0.1\lib\net45\Microsoft.Owin.Security.Cookies.dll - True + + ..\..\..\packages\Microsoft.IdentityModel.Protocols.WsFederation.5.7.0\lib\net461\Microsoft.IdentityModel.Protocols.WsFederation.dll - - ..\..\..\packages\Microsoft.Owin.Security.Facebook.3.0.1\lib\net45\Microsoft.Owin.Security.Facebook.dll - True + + ..\..\..\packages\Microsoft.IdentityModel.Tokens.5.7.0\lib\net461\Microsoft.IdentityModel.Tokens.dll - - ..\..\..\packages\Microsoft.Owin.Security.Google.3.0.1\lib\net45\Microsoft.Owin.Security.Google.dll - True + + ..\..\..\packages\Microsoft.IdentityModel.Tokens.Saml.5.7.0\lib\net461\Microsoft.IdentityModel.Tokens.Saml.dll - - ..\..\..\packages\Microsoft.Owin.Security.Jwt.3.0.1\lib\net45\Microsoft.Owin.Security.Jwt.dll - True + + ..\..\..\packages\Microsoft.IdentityModel.Xml.5.7.0\lib\net461\Microsoft.IdentityModel.Xml.dll - - ..\..\..\packages\Microsoft.Owin.Security.OAuth.3.0.1\lib\net45\Microsoft.Owin.Security.OAuth.dll - True + + ..\..\..\packages\Microsoft.Owin.4.2.2\lib\net45\Microsoft.Owin.dll - - ..\..\..\packages\Microsoft.Owin.Security.OpenIdConnect.3.0.1\lib\net45\Microsoft.Owin.Security.OpenIdConnect.dll - True + + ..\..\..\packages\Microsoft.Owin.Host.SystemWeb.4.2.2\lib\net45\Microsoft.Owin.Host.SystemWeb.dll - - ..\..\..\packages\Microsoft.Owin.Security.Twitter.3.0.1\lib\net45\Microsoft.Owin.Security.Twitter.dll - True + + ..\..\..\packages\Microsoft.Owin.Security.4.2.2\lib\net45\Microsoft.Owin.Security.dll + + + ..\..\..\packages\Microsoft.Owin.Security.ActiveDirectory.4.2.2\lib\net45\Microsoft.Owin.Security.ActiveDirectory.dll + + + ..\..\..\packages\Microsoft.Owin.Security.Cookies.4.2.2\lib\net45\Microsoft.Owin.Security.Cookies.dll + + + ..\..\..\packages\Microsoft.Owin.Security.Facebook.4.2.2\lib\net45\Microsoft.Owin.Security.Facebook.dll + + + ..\..\..\packages\Microsoft.Owin.Security.Google.4.2.2\lib\net45\Microsoft.Owin.Security.Google.dll + + + ..\..\..\packages\Microsoft.Owin.Security.Jwt.4.2.2\lib\net45\Microsoft.Owin.Security.Jwt.dll + + + ..\..\..\packages\Microsoft.Owin.Security.OAuth.4.2.2\lib\net45\Microsoft.Owin.Security.OAuth.dll + + + ..\..\..\packages\Microsoft.Owin.Security.OpenIdConnect.4.2.2\lib\net45\Microsoft.Owin.Security.OpenIdConnect.dll + + + ..\..\..\packages\Microsoft.Owin.Security.Twitter.4.2.2\lib\net45\Microsoft.Owin.Security.Twitter.dll ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll True - - ..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True + + ..\..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll - - ..\..\..\packages\NHibernate.4.0.1.4000\lib\net40\NHibernate.dll - True + + ..\..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll ..\..\..\packages\Owin.1.0\lib\net40\Owin.dll True + + ..\..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll + + + ..\..\..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll + @@ -148,47 +171,43 @@ - - ..\..\..\packages\System.IdentityModel.Tokens.Jwt.4.0.2.206221351\lib\net45\System.IdentityModel.Tokens.Jwt.dll - True + + ..\..\..\packages\System.IdentityModel.Tokens.Jwt.5.7.0\lib\net461\System.IdentityModel.Tokens.Jwt.dll + + - - ..\..\..\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll + + ..\..\..\packages\System.Spatial.5.8.4\lib\net40\System.Spatial.dll True + - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True - - - False - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll + - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -222,6 +241,7 @@ + @@ -252,20 +272,22 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {d10ad48f-407d-4db5-a328-173ec7cb010f} Orchard.Roles + $(MvcBuildViews) {79AED36E-ABD0-4747-93D3-8722B042454B} Orchard.Users + $(MvcBuildViews) @@ -323,7 +345,7 @@ --> - + diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/ActiveDirectoryFederationServices.cs b/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/ActiveDirectoryFederationServices.cs index 6107b1d5e26..24aca801adc 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/ActiveDirectoryFederationServices.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/ActiveDirectoryFederationServices.cs @@ -20,7 +20,7 @@ public ActiveDirectoryFederationServices(IWorkContextAccessor workContextAccesso public IEnumerable GetOwinMiddlewares() { var settings = _workContextAccessor.GetContext().CurrentSite.As(); - if (settings == null || !settings.IsValid) { + if (settings == null || !settings.IsValid()) { return Enumerable.Empty(); } diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/AzureActiveDirectory.cs b/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/AzureActiveDirectory.cs index bb8736d2a29..49b39186b65 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/AzureActiveDirectory.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/AzureActiveDirectory.cs @@ -52,7 +52,7 @@ public IEnumerable GetOwinMiddlewares() { var azureWebSiteProtectionEnabled = false; var azureUseAzureGraphApi = false; - if (settings == null || !settings.IsValid) { + if (settings == null || !settings.IsValid()) { return Enumerable.Empty(); } @@ -60,6 +60,7 @@ public IEnumerable GetOwinMiddlewares() { _azureTenant = settings.Tenant; _azureAdInstance = settings.ADInstance; _azureGraphApiUri = settings.GraphApiUrl; + _azureGraphApiKey = settings.GraphApiKey; logoutRedirectUri = settings.LogoutRedirectUri; azureWebSiteProtectionEnabled = settings.AzureWebSiteProtectionEnabled; azureAppKey = settings.AppKey; @@ -87,13 +88,16 @@ public IEnumerable GetOwinMiddlewares() { AuthenticationFailed = context => { context.HandleResponse(); context.Response.Redirect(Constants.General.AuthenticationErrorUrl); - + Logger.Debug(context.Exception, "AAD authentication failed."); return Task.FromResult(0); } } - }; + // Allowing login from all AAD tenants (so with any Microsoft ID). We'd need to list all possible AAD tenants + // here otherwise. + openIdOptions.TokenValidationParameters.ValidateIssuer = false; + if (azureWebSiteProtectionEnabled) { middlewares.Add(new OwinMiddlewareRegistration { Priority = "9", diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/Facebook.cs b/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/Facebook.cs index 0b6cfdc06fa..cd1f1ef7e05 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/Facebook.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/Facebook.cs @@ -18,7 +18,7 @@ public Facebook(IWorkContextAccessor workContextAccessor) { public IEnumerable GetOwinMiddlewares() { var settings = _workContextAccessor.GetContext().CurrentSite.As(); - if (settings == null || !settings.IsValid) { + if (settings == null || !settings.IsValid()) { return Enumerable.Empty(); } diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/Google.cs b/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/Google.cs index 926cacc3a45..f1f4beecebf 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/Google.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/Google.cs @@ -3,6 +3,7 @@ using Microsoft.Owin; using Microsoft.Owin.Security.Google; using Orchard.ContentManagement; +using Orchard.Environment.Configuration; using Orchard.Environment.Extensions; using Orchard.OpenId.Models; using Orchard.Owin; @@ -18,16 +19,17 @@ public Google(IWorkContextAccessor workContextAccessor) { } public IEnumerable GetOwinMiddlewares() { - var settings = _workContextAccessor.GetContext().CurrentSite.As(); + var workContext = _workContextAccessor.GetContext(); + var settings = workContext.CurrentSite.As(); - if (settings == null || !settings.IsValid) { + if (settings == null || !settings.IsValid()) { return Enumerable.Empty(); } var authenticationOptions = new GoogleOAuth2AuthenticationOptions { ClientId = settings.ClientId, ClientSecret = settings.ClientSecret, - CallbackPath = new PathString(settings.CallbackPath) + CallbackPath = new PathString(GetCallbackPath(workContext, settings)) }; return new List { @@ -39,5 +41,16 @@ public IEnumerable GetOwinMiddlewares() { } }; } + + private string GetCallbackPath(WorkContext workContext, GoogleSettingsPart settings) { + var shellSettings = workContext.Resolve(); + var tenantPrefix = shellSettings.RequestUrlPrefix; + + var callbackUrl = string.IsNullOrWhiteSpace(tenantPrefix) ? + settings.CallbackPath : + string.Format("/{0}{1}", tenantPrefix, settings.CallbackPath); + + return callbackUrl; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/Twitter.cs b/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/Twitter.cs index 5f79f10eadb..0f3b00cfe6b 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/Twitter.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/OwinMiddlewares/Twitter.cs @@ -20,7 +20,7 @@ public Twitter(IWorkContextAccessor workContextAccessor) { public IEnumerable GetOwinMiddlewares() { var settings = _workContextAccessor.GetContext().CurrentSite.As(); - if (settings == null || !settings.IsValid) { + if (settings == null || !settings.IsValid()) { return Enumerable.Empty(); } diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Providers/ActiveDirectoryFederationServices.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Providers/ActiveDirectoryFederationServices.cs index a1e89d159c6..b1185078bf6 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Providers/ActiveDirectoryFederationServices.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Providers/ActiveDirectoryFederationServices.cs @@ -42,7 +42,7 @@ private bool IsProviderValid() { site = scope.Resolve().GetSiteSettings(); settings = site.As(); - return (settings != null && settings.IsValid); + return (settings != null && settings.IsValid()); } catch (Exception) { return false; diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Providers/AzureActiveDirectory.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Providers/AzureActiveDirectory.cs index 13ee6124f1f..747d38bc9c6 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Providers/AzureActiveDirectory.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Providers/AzureActiveDirectory.cs @@ -42,7 +42,7 @@ private bool IsProviderValid() { site = scope.Resolve().GetSiteSettings(); settings = site.As(); - return (settings != null && settings.IsValid); + return (settings != null && settings.IsValid()); } catch (Exception) { return false; diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Providers/Facebook.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Providers/Facebook.cs index 018d985d069..b0ee90f4ef8 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Providers/Facebook.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Providers/Facebook.cs @@ -42,7 +42,7 @@ private bool IsProviderValid() { site = scope.Resolve().GetSiteSettings(); settings = site.As(); - return (settings != null && settings.IsValid); + return (settings != null && settings.IsValid()); } catch (Exception) { return false; diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Providers/Google.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Providers/Google.cs index 0f1031bf03c..5e1d3a7f409 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Providers/Google.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Providers/Google.cs @@ -43,7 +43,7 @@ private bool IsProviderValid() { site = scope.Resolve().GetSiteSettings(); settings = site.As(); - return (settings != null && settings.IsValid); + return (settings != null && settings.IsValid()); } catch (Exception) { return false; diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Providers/Twitter.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Providers/Twitter.cs index 2b998fbb067..4d873f796fc 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Providers/Twitter.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Providers/Twitter.cs @@ -42,7 +42,7 @@ private bool IsProviderValid() { site = scope.Resolve().GetSiteSettings(); settings = site.As(); - return (settings != null && settings.IsValid); + return (settings != null && settings.IsValid()); } catch (Exception) { return false; diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Routes/OpenId.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Routes/OpenId.cs index 72668557720..5053cb09d74 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Routes/OpenId.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Routes/OpenId.cs @@ -14,16 +14,10 @@ public OpenIdRoutes(IEnumerable openIdProviders) { } public void GetRoutes(ICollection routes) { - foreach (var route in GetRoutes()) { - routes.Add(route); - } - } - - public IEnumerable GetRoutes() { if (IsAnyProviderSettingsValid() == false) - return Enumerable.Empty(); + return; - return new[] { + var routeDescriptors = new[] { new RouteDescriptor { Priority = 11, Route = new Route( @@ -126,6 +120,10 @@ public IEnumerable GetRoutes() { new MvcRouteHandler()) } }; + + foreach (var routeDescriptor in routeDescriptors) { + routes.Add(routeDescriptor); + } } private bool IsAnyProviderSettingsValid() { diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Services/ActiveDirectoryFederationServices/MissingSettingsBanner.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Services/ActiveDirectoryFederationServices/MissingSettingsBanner.cs index 2f2e0b2e991..01a29062218 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Services/ActiveDirectoryFederationServices/MissingSettingsBanner.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Services/ActiveDirectoryFederationServices/MissingSettingsBanner.cs @@ -26,7 +26,7 @@ public IEnumerable GetNotifications() { var workContext = _orchardServices.WorkContext; var settings = workContext.CurrentSite.As(); - if (settings == null || !settings.IsValid) { + if (settings == null || !settings.IsValid()) { var url = _urlHelper.Action("OpenId", "Admin", new { Area = "Settings" }); yield return new NotifyEntry { Message = T("The Active Directory Federation Services settings need to be configured.", url), Type = NotifyType.Warning }; } diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Services/AzureActiveDirectory/MissingSettingsBanner.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Services/AzureActiveDirectory/MissingSettingsBanner.cs index 48dd143c5aa..1f82138c3e1 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Services/AzureActiveDirectory/MissingSettingsBanner.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Services/AzureActiveDirectory/MissingSettingsBanner.cs @@ -27,7 +27,7 @@ public IEnumerable GetNotifications() { var workContext = _orchardServices.WorkContext; var azureSettings = workContext.CurrentSite.As(); - if (azureSettings == null || !azureSettings.IsValid) { + if (azureSettings == null || !azureSettings.IsValid()) { var url = _urlHelper.Action("OpenId", "Admin", new { Area = "Settings" }); yield return new NotifyEntry { Message = T("The Azure AD Authentication settings need to be configured.", url), Type = NotifyType.Warning }; } diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Services/Facebook/MissingSettingsBanner.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Services/Facebook/MissingSettingsBanner.cs index 011aac000a8..1b8441fb84c 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Services/Facebook/MissingSettingsBanner.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Services/Facebook/MissingSettingsBanner.cs @@ -27,7 +27,7 @@ public IEnumerable GetNotifications() { var workContext = _orchardServices.WorkContext; var settings = workContext.CurrentSite.As(); - if (settings == null || !settings.IsValid) { + if (settings == null || !settings.IsValid()) { var url = _urlHelper.Action("OpenId", "Admin", new { Area = "Settings" }); yield return new NotifyEntry { Message = T("The Facebook settings need to be configured.", url), Type = NotifyType.Warning }; } diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Services/Google/MissingSettingsBanner.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Services/Google/MissingSettingsBanner.cs index 6888a12e894..b799fd37dbe 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Services/Google/MissingSettingsBanner.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Services/Google/MissingSettingsBanner.cs @@ -27,7 +27,7 @@ public IEnumerable GetNotifications() { var workContext = _orchardServices.WorkContext; var settings = workContext.CurrentSite.As(); - if (settings == null || !settings.IsValid) { + if (settings == null || !settings.IsValid()) { var url = _urlHelper.Action("OpenId", "Admin", new { Area = "Settings" }); yield return new NotifyEntry { Message = T("The Google settings need to be configured.", url), Type = NotifyType.Warning }; } diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Services/IOpenIdAuthenticationService.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Services/IOpenIdAuthenticationService.cs new file mode 100644 index 00000000000..c26bb122787 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Services/IOpenIdAuthenticationService.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Orchard.OpenId.Services { + public interface IOpenIdAuthenticationService : IDependency { + bool IsLocalUser(); + } +} diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Services/OpenIdAuthenticationService.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Services/OpenIdAuthenticationService.cs index 42d6942d0a3..8f146ced241 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Services/OpenIdAuthenticationService.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Services/OpenIdAuthenticationService.cs @@ -5,13 +5,14 @@ using Orchard.Environment.Configuration; using Orchard.Environment.Extensions; using Orchard.Mvc; +using Orchard.Mvc.Extensions; using Orchard.Security; using Orchard.Security.Providers; using Orchard.Services; namespace Orchard.OpenId.Services { [OrchardFeature("Orchard.OpenId")] - public class OpenIdAuthenticationService : IAuthenticationService { + public class OpenIdAuthenticationService : IAuthenticationService, IOpenIdAuthenticationService { private readonly ShellSettings _settings; private readonly IClock _clock; private readonly IMembershipService _membershipService; @@ -19,6 +20,8 @@ public class OpenIdAuthenticationService : IAuthenticationService { private readonly IHttpContextAccessor _httpContextAccessor; private readonly IMembershipValidationService _membershipValidationService; private readonly IEnumerable _openIdProviders; + private readonly IEnumerable _userDataProviders; + private readonly ISecurityService _securityService; private IUser _localAuthenticationUser; @@ -26,7 +29,7 @@ public class OpenIdAuthenticationService : IAuthenticationService { private IAuthenticationService FallbackAuthenticationService { get { if (_fallbackAuthenticationService == null) - _fallbackAuthenticationService = new FormsAuthenticationService(_settings, _clock, _membershipService, _httpContextAccessor, _sslSettingsProvider, _membershipValidationService); + _fallbackAuthenticationService = new FormsAuthenticationService(_settings, _clock, _membershipService, _httpContextAccessor, _sslSettingsProvider, _membershipValidationService, _userDataProviders, _securityService); return _fallbackAuthenticationService; } @@ -39,7 +42,9 @@ public OpenIdAuthenticationService( ISslSettingsProvider sslSettingsProvider, IHttpContextAccessor httpContextAccessor, IMembershipValidationService membershipValidationService, - IEnumerable openIdProviders) { + IEnumerable openIdProviders, + IEnumerable userDataProviders, + ISecurityService securityService) { _httpContextAccessor = httpContextAccessor; _membershipService = membershipService; @@ -48,6 +53,8 @@ public OpenIdAuthenticationService( _sslSettingsProvider = sslSettingsProvider; _membershipValidationService = membershipValidationService; _openIdProviders = openIdProviders; + _userDataProviders = userDataProviders; + _securityService = securityService; } public void SignIn(IUser user, bool createPersistentCookie) { @@ -73,9 +80,9 @@ public IUser GetAuthenticatedUser() { return FallbackAuthenticationService.GetAuthenticatedUser(); } - var user = _httpContextAccessor.Current().GetOwinContext().Authentication.User; + var userIdentity = _httpContextAccessor.Current().GetOwinContext().Authentication.User.Identity; - if (!user.Identity.IsAuthenticated) { + if (string.IsNullOrEmpty(userIdentity.Name?.Trim()) || !userIdentity.IsAuthenticated) { return null; } @@ -84,20 +91,26 @@ public IUser GetAuthenticatedUser() { return _localAuthenticationUser; } - var userName = user.Identity.Name.Trim(); + var userName = userIdentity.Name.Trim(); //Get the local user, if local user account doesn't exist, create it var localUser = _membershipService.GetUser(userName) ?? _membershipService.CreateUser(new CreateUserParams( - userName, Membership.GeneratePassword(16, 1), userName, string.Empty, string.Empty, true + userName, Membership.GeneratePassword(16, 1), userName, string.Empty, string.Empty, true, false )); return _localAuthenticationUser = localUser; } - private bool IsLocalUser() { - var anyClaim = _httpContextAccessor.Current().GetOwinContext().Authentication.User.Claims.FirstOrDefault(); + public bool IsLocalUser() { + var httpContext = _httpContextAccessor.Current(); + + if (httpContext.IsBackgroundContext()) { + return true; + } + + var anyClaim = httpContext.GetOwinContext().Authentication.User.Claims.FirstOrDefault(); if (anyClaim == null || anyClaim.Issuer == Constants.General.LocalIssuer || anyClaim.Issuer == Constants.General.FormsIssuer) { return true; diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Services/Twitter/MissingSettingsBanner.cs b/src/Orchard.Web/Modules/Orchard.OpenId/Services/Twitter/MissingSettingsBanner.cs index abb8600a269..f8df37f4242 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Services/Twitter/MissingSettingsBanner.cs +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Services/Twitter/MissingSettingsBanner.cs @@ -27,7 +27,7 @@ public IEnumerable GetNotifications() { var workContext = _orchardServices.WorkContext; var settings = workContext.CurrentSite.As(); - if (settings == null || !settings.IsValid) { + if (settings == null || !settings.IsValid()) { var url = _urlHelper.Action("OpenId", "Admin", new { Area = "Settings" }); yield return new NotifyEntry { Message = T("The Twitter settings need to be configured.", url), Type = NotifyType.Warning }; } diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Views/Account/Error.cshtml b/src/Orchard.Web/Modules/Orchard.OpenId/Views/Account/Error.cshtml index d4190517ec1..f61d284ec2c 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Views/Account/Error.cshtml +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Views/Account/Error.cshtml @@ -1 +1 @@ -@T("Oops, Something went wrong with your authentication!") +@T("Oops, something went wrong with your authentication!") diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Views/Account/Logon.cshtml b/src/Orchard.Web/Modules/Orchard.OpenId/Views/Account/Logon.cshtml index d2e61b04c4b..5a6c7753355 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Views/Account/Logon.cshtml +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Views/Account/Logon.cshtml @@ -2,10 +2,10 @@ @using Orchard.OpenId.Services @using Orchard.Utility.Extensions -

        Logon

        +

        @T("Logon")


        -@using (Html.BeginFormAntiForgeryPost(Url.Action("LogOn", "Account", new { Area = "Orchard.Users", ReturnUrl = Request.QueryString["ReturnUrl"] }))) { +@using (Html.BeginFormAntiForgeryPost(Url.Action("LogOn", "Account", new { Area = "Orchard.OpenId", ReturnUrl = Request.QueryString["ReturnUrl"] }))) { }
        -
        Or choose your OpenId account provider
        +
        @T("Or choose your OpenId account provider")

        @foreach (var provider in Model) { if (provider.IsValid) { - + @provider.DisplayName } diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.ActiveDirectoryFederationServicesSettings.cshtml b/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.ActiveDirectoryFederationServicesSettings.cshtml index 8cbe78198bf..012cd00df0f 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.ActiveDirectoryFederationServicesSettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.ActiveDirectoryFederationServicesSettings.cshtml @@ -3,17 +3,17 @@

        Active Directory Federation Services Settings

        - @Html.LabelFor(m => m.ClientId, T("Client Id")) + @Html.TextBoxFor(m => m.ClientId, new { @class = "text large" }) @T("ADFS's Client Id obtained from your ADFS configuration (e.g. {0})", ActiveDirectoryFederationServices.DefaultClientId)
        - @Html.LabelFor(m => m.MetadataAddress, T("Metadata Address")) + @Html.TextBoxFor(m => m.MetadataAddress, new { @class = "text large" }) @T("ADFS's Metadata Address url obtained from your ADFS configuration (e.g. {0})", ActiveDirectoryFederationServices.DefaultMetadataAddress)
        - @Html.LabelFor(m => m.PostLogoutRedirectUri, T("Post Logout Redirect Uri")) + @Html.TextBoxFor(m => m.PostLogoutRedirectUri, new { @class = "text large" }) @T("ADFS's Post Logout Redirect url obtained from your ADFS configuration (e.g. {0})", ActiveDirectoryFederationServices.DefaultPostLogoutRedirectUri)
        diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.AzureActiveDirectorySettings.cshtml b/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.AzureActiveDirectorySettings.cshtml index e014536fb3b..6aa0f6b026b 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.AzureActiveDirectorySettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.AzureActiveDirectorySettings.cshtml @@ -2,31 +2,31 @@

        Azure Active Directory Settings

        - @Html.LabelFor(m => m.Tenant, T("Tenant")) + @Html.TextBoxFor(m => m.Tenant, new { @class = "text large" }) @T("Azure Active Directory tenant (e.g. yoursite.onmicrosoft.com).")
        - @Html.LabelFor(m => m.ADInstance, T("Active Directory Instance")) + @Html.TextBoxFor(m => m.ADInstance, new { @class = "text large" }) @T("Default instance is https://login.microsoftonline.com/{your-tenant-name}")
        - @Html.LabelFor(m => m.ClientId, T("App ID")) + @Html.TextBoxFor(m => m.ClientId, new { @class = "text large" })
        - @Html.LabelFor(m => m.AppName, T("App Name")) + @Html.TextBoxFor(m => m.AppName, new { @class = "text large" }) @T("The application name you wish to give active directory login rights to.")
        - @Html.LabelFor(m => m.LogoutRedirectUri, T("Logout Redirect")) + @Html.TextBoxFor(m => m.LogoutRedirectUri, new { @class = "text large" }) @T("Redirect url after azure logout, default is http://localhost:30321/OrchardLocal/")
        - @Html.LabelFor(m => m.ServiceResourceID, T("Service Resource ID")) + @Html.TextAreaFor(m => m.ServiceResourceID, new { @class = "text large" }) @T(@"If you have a single 'Service Resource ID' just write it down directly. @@ -35,29 +35,32 @@
        - @Html.LabelFor(m => m.AppKey, T("App Key")) + @Html.TextBoxFor(m => m.AppKey, new { @class = "text large" })
        @Html.CheckBoxFor(m => m.BearerAuthEnabled) - +
        @Html.CheckBoxFor(m => m.SSLEnabled) - +
        @Html.CheckBoxFor(m => m.AzureWebSiteProtectionEnabled) - +
        @Html.CheckBoxFor(m => m.UseAzureGraphApi) - + @T("Check this box to enable syncing Orchard Role membership to Azure Graph API Group Membership. This module will not create new Orchard Roles for you, but it will sync up user membership of existing Orchard Roles with AD Group membership for Role names that match a group name")
        - @Html.LabelFor(m => m.GraphApiUrl, T("Graph API URL")) + @Html.TextBoxFor(m => m.GraphApiUrl, new { @class = "text large" }) @T("Typically https://graph.windows.net") + + + @Html.TextBoxFor(m => m.GraphApiKey, new { @class = "text large" })

        \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.FacebookSettings.cshtml b/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.FacebookSettings.cshtml index 3979e5f04a7..26739509a4f 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.FacebookSettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.FacebookSettings.cshtml @@ -3,12 +3,12 @@

        Facebook Settings

        - @Html.LabelFor(m => m.AppId, T("App Id")) + @Html.TextBoxFor(m => m.AppId, new { @class = "text large" }) @T("Facebook's App Id obtained from your facebook developer dashboard (e.g. {0})", Facebook.DefaultAppId)
        - @Html.LabelFor(m => m.AppSecret, T("App Secret")) + @Html.TextBoxFor(m => m.AppSecret, new { @class = "text large" }) @T("Facebook's App Secret obtained from your facebook developer dashboard (e.g. {0})", Facebook.DefaultAppSecret)
        diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.GoogleSettings.cshtml b/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.GoogleSettings.cshtml index b2d584159e1..c43106a5d18 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.GoogleSettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.GoogleSettings.cshtml @@ -3,17 +3,17 @@

        Google Settings

        - @Html.LabelFor(m => m.ClientId, T("Client Id")) + @Html.TextBoxFor(m => m.ClientId, new { @class = "text large" }) @T("Google's Client Id obtained from your google dashboard (e.g. {0})", Google.DefaultClientId)
        - @Html.LabelFor(m => m.ClientSecret, T("Client Secret")) + @Html.TextBoxFor(m => m.ClientSecret, new { @class = "text large" }) @T("Google's Client Secret obtained from your google dashboard (e.g. {0})", Google.DefaultClientSecret)
        - @Html.LabelFor(m => m.CallbackPath, T("Callback Path")) + @Html.TextBoxFor(m => m.CallbackPath, new { @class = "text large" }) @T("Google's Callback Path obtained from your google dashboard (case sensitive). Recommended: {0}", General.LogonCallbackUrl)
        diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.TwitterSettings.cshtml b/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.TwitterSettings.cshtml index 99f674d089b..ee4a32d3878 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.TwitterSettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Views/EditorTemplates/Parts.TwitterSettings.cshtml @@ -9,12 +9,12 @@

        @T("Twitter Settings")

        - @Html.LabelFor(m => m.ConsumerKey, T("Consumer Key")) + @Html.TextBoxFor(m => m.ConsumerKey, new { @class = "text large" }) @T("Twitter's Consumer Key obtained from your twitter dashboard (e.g. {0})", Twitter.DefaultConsumerKey)
        - @Html.LabelFor(m => m.ConsumerSecret, T("Consumer Secret")) + @Html.TextBoxFor(m => m.ConsumerSecret, new { @class = "text large" }) @T("Twitter's Consumer Secret obtained from your twitter dashboard (e.g. {0})", Twitter.DefaultConsumerSecret)
        @@ -26,22 +26,22 @@
        @T("These settings rarely change, it is recommended to keep default values") - @Html.LabelFor(m => m.VeriSignClass3SecureServerCA_G2, T("VeriSign Class3 Secure Server CA - G2")) + @Html.TextBoxFor(m => m.VeriSignClass3SecureServerCA_G2, new { @class = "text large" }) - @Html.LabelFor(m => m.VeriSignClass3SecureServerCA_G3, T("VeriSign Class3 Secure Server CA - G3")) + @Html.TextBoxFor(m => m.VeriSignClass3SecureServerCA_G3, new { @class = "text large" }) - @Html.LabelFor(m => m.VeriSignClass3PublicPrimaryCA_G5, T("VeriSign Class3 Secure Server CA - G5")) + @Html.TextBoxFor(m => m.VeriSignClass3PublicPrimaryCA_G5, new { @class = "text large" }) - @Html.LabelFor(m => m.SymantecClass3SecureServerCA_G4, T("Symantec Class3 Secure Server CA - G4")) + @Html.TextBoxFor(m => m.SymantecClass3SecureServerCA_G4, new { @class = "text large" }) - @Html.LabelFor(m => m.DigiCertSHA2HighAssuranceServerCA, T("DigiCert SHA2 High Assurance Server CA")) + @Html.TextBoxFor(m => m.DigiCertSHA2HighAssuranceServerCA, new { @class = "text large" }) - @Html.LabelFor(m => m.DigiCertHighAssuranceEVRootCA, T("DigiCert High Assurance EV Root CA")) + @Html.TextBoxFor(m => m.DigiCertHighAssuranceEVRootCA, new { @class = "text large" })
        diff --git a/src/Orchard.Web/Modules/Orchard.OpenId/Views/User.cshtml b/src/Orchard.Web/Modules/Orchard.OpenId/Views/User.cshtml index b4415b4fe93..706ab005e1a 100644 --- a/src/Orchard.Web/Modules/Orchard.OpenId/Views/User.cshtml +++ b/src/Orchard.Web/Modules/Orchard.OpenId/Views/User.cshtml @@ -1,7 +1,18 @@ -
        +@using System.Web.Mvc; + +
        @if (WorkContext.CurrentUser != null) { + IHtmlString userNameDisplayHtml; + + if (WorkContext.Resolve().IsLocalUser()) { + userNameDisplayHtml = Html.Raw("" + Html.ItemDisplayText(WorkContext.CurrentUser) + ""); + } + else { + userNameDisplayHtml = Html.ItemDisplayText(WorkContext.CurrentUser); + } +
        /// DateTime is stored in UTC but entered in local - protected static DateTime GetLowBoundPattern(string datePattern) { - var match = _dateRegEx.Match(datePattern); - - return DateTime.Parse( - String.Format("{0}-{1}-{2} {3}:{4}:{5}", - match.Groups["year"].Success ? match.Groups["year"].Value : "1980", - match.Groups["month"].Success ? match.Groups["month"].Value : "01", - match.Groups["day"].Success ? match.Groups["day"].Value : "01", - match.Groups["hour"].Success ? match.Groups["hour"].Value : "00", - match.Groups["minute"].Success ? match.Groups["minute"].Value : "00", - match.Groups["second"].Success ? match.Groups["second"].Value : "00"), - CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal); + protected static DateTime? GetLowBoundPattern(string datePattern) { + if (string.IsNullOrEmpty(datePattern)) { + return null; + } + else { + var match = _dateRegEx.Match(datePattern); + + return DateTime.Parse( + String.Format("{0}-{1}-{2} {3}:{4}:{5}", + match.Groups["year"].Success ? match.Groups["year"].Value : "1980", + match.Groups["month"].Success ? match.Groups["month"].Value : "01", + match.Groups["day"].Success ? match.Groups["day"].Value : "01", + match.Groups["hour"].Success ? match.Groups["hour"].Value : "00", + match.Groups["minute"].Success ? match.Groups["minute"].Value : "00", + match.Groups["second"].Success ? match.Groups["second"].Value : "00"), + CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal); + } } protected static DateTime ApplyDelta(DateTime now, string unit, int value) { @@ -230,40 +265,48 @@ protected static DateTime ApplyDelta(DateTime now, string unit, int value) { public static LocalizedString DisplayFilter(string fieldName, dynamic formState, Localizer T) { var op = (DateTimeOperator)Enum.Parse(typeof(DateTimeOperator), Convert.ToString(formState.Operator)); - string type = Convert.ToString(formState.ValueType); - string value = Convert.ToString(formState.Value); - string min = Convert.ToString(formState.Min); - string max = Convert.ToString(formState.Max); - string valueUnit = Convert.ToString(formState.ValueUnit); - string minUnit = Convert.ToString(formState.MinUnit); - string maxUnit = Convert.ToString(formState.MaxUnit); - - if (type == "0") { - valueUnit = minUnit = maxUnit = String.Empty; - } + + if (op == DateTimeOperator.IsNull) + return T("{0} is null", fieldName); + else + if (op == DateTimeOperator.IsNotNull) + return T("{0} is not null", fieldName); else { - valueUnit = " " + valueUnit; - minUnit = " " + minUnit; - maxUnit = " " + maxUnit; - } + string type = Convert.ToString(formState.ValueType); + string value = Convert.ToString(formState.Value); + string min = Convert.ToString(formState.Min); + string max = Convert.ToString(formState.Max); + string valueUnit = Convert.ToString(formState.ValueUnit); + string minUnit = Convert.ToString(formState.MinUnit); + string maxUnit = Convert.ToString(formState.MaxUnit); + + if (type == "0") { + valueUnit = minUnit = maxUnit = String.Empty; + } + else { + valueUnit = " " + valueUnit; + minUnit = " " + minUnit; + maxUnit = " " + maxUnit; + } - switch (op) { - case DateTimeOperator.LessThan: - return T("{0} is less than {1}{2}", fieldName, value, T(valueUnit)); - case DateTimeOperator.LessThanEquals: - return T("{0} is less than or equal to {1}{2}", fieldName, value, T(valueUnit)); - case DateTimeOperator.Equals: - return T("{0} equals {1}{2}", fieldName, value, T(valueUnit)); - case DateTimeOperator.NotEquals: - return T("{0} is not equal to {1}{2}", fieldName, value, T(valueUnit)); - case DateTimeOperator.GreaterThan: - return T("{0} is greater than {1}{2}", fieldName, value, T(valueUnit)); - case DateTimeOperator.GreaterThanEquals: - return T("{0} is greater than or equal to {1}{2}", fieldName, value, T(valueUnit)); - case DateTimeOperator.Between: - return T("{0} is between {1}{2} and {3}{4}", fieldName, min, T(minUnit), max, T(maxUnit)); - case DateTimeOperator.NotBetween: - return T("{0} is not between {1}{2} and {3}{4}", fieldName, min, T(minUnit), max, T(maxUnit)); + switch (op) { + case DateTimeOperator.LessThan: + return T("{0} is less than {1}{2}", fieldName, value, T(valueUnit)); + case DateTimeOperator.LessThanEquals: + return T("{0} is less than or equal to {1}{2}", fieldName, value, T(valueUnit)); + case DateTimeOperator.Equals: + return T("{0} equals {1}{2}", fieldName, value, T(valueUnit)); + case DateTimeOperator.NotEquals: + return T("{0} is not equal to {1}{2}", fieldName, value, T(valueUnit)); + case DateTimeOperator.GreaterThan: + return T("{0} is greater than {1}{2}", fieldName, value, T(valueUnit)); + case DateTimeOperator.GreaterThanEquals: + return T("{0} is greater than or equal to {1}{2}", fieldName, value, T(valueUnit)); + case DateTimeOperator.Between: + return T("{0} is between {1}{2} and {3}{4}", fieldName, min, T(minUnit), max, T(maxUnit)); + case DateTimeOperator.NotBetween: + return T("{0} is not between {1}{2} and {3}{4}", fieldName, min, T(minUnit), max, T(maxUnit)); + } } // should never be hit, but fail safe @@ -274,19 +317,24 @@ public static LocalizedString DisplayFilter(string fieldName, dynamic formState, /// Returns the low bound value of a date pattern. e.g., 2011-10 will return 2011-10-01 00:00:00 /// /// DateTime is stored in UTC but entered in local - protected static DateTime GetHighBoundPattern(string datePattern) { - var match = _dateRegEx.Match(datePattern); - - string year, month; - return DateTime.Parse( - String.Format("{0}-{1}-{2} {3}:{4}:{5}", - year = match.Groups["year"].Success ? match.Groups["year"].Value : "2099", - month = match.Groups["month"].Success ? match.Groups["month"].Value : "12", - match.Groups["day"].Success ? match.Groups["day"].Value : DateTime.DaysInMonth(Int32.Parse(year), Int32.Parse(month)).ToString(), - match.Groups["hour"].Success ? match.Groups["hour"].Value : "23", - match.Groups["minute"].Success ? match.Groups["minute"].Value : "59", - match.Groups["second"].Success ? match.Groups["second"].Value : "59"), - CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal); + protected static DateTime? GetHighBoundPattern(string datePattern) { + if (string.IsNullOrEmpty(datePattern)) { + return null; + } + else { + var match = _dateRegEx.Match(datePattern); + + string year, month; + return DateTime.Parse( + String.Format("{0}-{1}-{2} {3}:{4}:{5}", + year = match.Groups["year"].Success ? match.Groups["year"].Value : "2099", + month = match.Groups["month"].Success ? match.Groups["month"].Value : "12", + match.Groups["day"].Success ? match.Groups["day"].Value : DateTime.DaysInMonth(Int32.Parse(year), Int32.Parse(month)).ToString(), + match.Groups["hour"].Success ? match.Groups["hour"].Value : "23", + match.Groups["minute"].Success ? match.Groups["minute"].Value : "59", + match.Groups["second"].Success ? match.Groups["second"].Value : "59"), + CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal); + } } } @@ -299,7 +347,9 @@ public enum DateTimeOperator { GreaterThan, GreaterThanEquals, Between, - NotBetween + NotBetween, + IsNull, + IsNotNull } public enum DateTimeSpan { diff --git a/src/Orchard.Web/Modules/Orchard.Projections/FilterEditors/Forms/DateTimeFormValidation.cs b/src/Orchard.Web/Modules/Orchard.Projections/FilterEditors/Forms/DateTimeFormValidation.cs index da376a9bcf2..53722916125 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/FilterEditors/Forms/DateTimeFormValidation.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/FilterEditors/Forms/DateTimeFormValidation.cs @@ -13,69 +13,76 @@ public class DateTimeFilterFormValidation : FormHandler { public override void Validating(ValidatingContext context) { if (context.FormName == DateTimeFilterForm.FormName) { - var isRange = new[] {"Between", "NotBetween"}.Contains(context.ValueProvider.GetValue("Operator").AttemptedValue); - var min = context.ValueProvider.GetValue("Min"); - var max = context.ValueProvider.GetValue("Max"); - var value = context.ValueProvider.GetValue("Value"); - var valueType = context.ValueProvider.GetValue("ValueType"); - - // validating mandatory values - if (isRange) { - if (min == null || String.IsNullOrWhiteSpace(min.AttemptedValue)) { - context.ModelState.AddModelError("Min", T("The field {0} is required.", T("Min").Text).Text); - } + var op = (DateTimeOperator)Enum.Parse(typeof(DateTimeOperator), Convert.ToString(context.ValueProvider.GetValue("Operator").AttemptedValue)); - if (max == null || String.IsNullOrWhiteSpace(max.AttemptedValue)) { - context.ModelState.AddModelError("Max", T("The field {0} is required.", T("Max").Text).Text); - } + if (op == DateTimeOperator.IsNull || op == DateTimeOperator.IsNotNull) { + // no further validation needed } else { - if (min == null || String.IsNullOrWhiteSpace(value.AttemptedValue)) { - context.ModelState.AddModelError("Value", T("The field {0} is required.", T("Value").Text).Text); - } - } - - if (!context.ModelState.IsValid) { - return; - } - - // validating data type - if (valueType.AttemptedValue == "0") { - // A date + var isRange = new[] {DateTimeOperator.Between, DateTimeOperator.NotBetween}.Contains(op); + var min = context.ValueProvider.GetValue("Min"); + var max = context.ValueProvider.GetValue("Max"); + var value = context.ValueProvider.GetValue("Value"); + var valueType = context.ValueProvider.GetValue("ValueType"); - if(isRange) { - if(!_dateRegEx.IsMatch(min.AttemptedValue) && !IsToken(min.AttemptedValue)) { - context.ModelState.AddModelError("Min", T("The field {0} should contain a valid date (YYYY-MM-DD hh:mm:ss)", T("Min").Text).Text); + // validating mandatory values + if (isRange) { + if (min == null || String.IsNullOrWhiteSpace(min.AttemptedValue)) { + context.ModelState.AddModelError("Min", T("The field {0} is required.", T("Min").Text).Text); } - if (!_dateRegEx.IsMatch(max.AttemptedValue) && !IsToken(max.AttemptedValue)) { - context.ModelState.AddModelError("Max", T("The field {0} should contain a valid date (YYYY-MM-DD hh:mm:ss)", T("Max").Text).Text); + if (max == null || String.IsNullOrWhiteSpace(max.AttemptedValue)) { + context.ModelState.AddModelError("Max", T("The field {0} is required.", T("Max").Text).Text); } } else { - if (!_dateRegEx.IsMatch(value.AttemptedValue) && !IsToken(value.AttemptedValue)) { - context.ModelState.AddModelError("Value", T("The field {0} should contain a valid date (YYYY-MM-DD hh:mm:ss)", T("Value").Text).Text); + if (min == null || String.IsNullOrWhiteSpace(value.AttemptedValue)) { + context.ModelState.AddModelError("Value", T("The field {0} is required.", T("Value").Text).Text); } } - } - else { - // An offset - int number; - if (isRange) { - if (!Int32.TryParse(min.AttemptedValue, out number) && !IsToken(min.AttemptedValue)) { - context.ModelState.AddModelError("Min", T("The field {0} must be a valid number.", T("Min").Text).Text); - } + if (!context.ModelState.IsValid) { + return; + } + + // validating data type + if (valueType.AttemptedValue == "0") { + // A date + + if(isRange) { + if(!_dateRegEx.IsMatch(min.AttemptedValue) && !IsToken(min.AttemptedValue)) { + context.ModelState.AddModelError("Min", T("The field {0} should contain a valid date (YYYY-MM-DD hh:mm:ss)", T("Min").Text).Text); + } - if (!Int32.TryParse(max.AttemptedValue, out number) && !IsToken(max.AttemptedValue)) { - context.ModelState.AddModelError("Max", T("The field {0} must be a valid number.", T("Max").Text).Text); + if (!_dateRegEx.IsMatch(max.AttemptedValue) && !IsToken(max.AttemptedValue)) { + context.ModelState.AddModelError("Max", T("The field {0} should contain a valid date (YYYY-MM-DD hh:mm:ss)", T("Max").Text).Text); + } } + else { + if (!_dateRegEx.IsMatch(value.AttemptedValue) && !IsToken(value.AttemptedValue)) { + context.ModelState.AddModelError("Value", T("The field {0} should contain a valid date (YYYY-MM-DD hh:mm:ss)", T("Value").Text).Text); + } + } + } else { - if (!Int32.TryParse(value.AttemptedValue, out number) && !IsToken(value.AttemptedValue)) { - context.ModelState.AddModelError("Value", T("The field {0} must be a valid number.", T("Value").Text).Text); + // An offset + int number; + if (isRange) { + if (!Int32.TryParse(min.AttemptedValue, out number) && !IsToken(min.AttemptedValue)) { + context.ModelState.AddModelError("Min", T("The field {0} must be a valid number.", T("Min").Text).Text); + } + + if (!Int32.TryParse(max.AttemptedValue, out number) && !IsToken(max.AttemptedValue)) { + context.ModelState.AddModelError("Max", T("The field {0} must be a valid number.", T("Max").Text).Text); + } } + else { + if (!Int32.TryParse(value.AttemptedValue, out number) && !IsToken(value.AttemptedValue)) { + context.ModelState.AddModelError("Value", T("The field {0} must be a valid number.", T("Value").Text).Text); + } + } } } } diff --git a/src/Orchard.Web/Modules/Orchard.Projections/FilterEditors/Forms/StringFilterForm.cs b/src/Orchard.Web/Modules/Orchard.Projections/FilterEditors/Forms/StringFilterForm.cs index bd13ead9cf7..4b88d245c2e 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/FilterEditors/Forms/StringFilterForm.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/FilterEditors/Forms/StringFilterForm.cs @@ -7,7 +7,6 @@ using Orchard.Localization; namespace Orchard.Projections.FilterEditors.Forms { - public class StringFilterForm : IFormProvider { public const string FormName = "StringFilter"; @@ -20,40 +19,44 @@ public StringFilterForm(IShapeFactory shapeFactory) { } public void Describe(DescribeContext context) { - Func form = - shape => { - - var f = Shape.Form( - Id: "StringFilter", - _Operator: Shape.SelectList( - Id: "operator", Name: "Operator", - Title: T("Operator"), - Size: 1, - Multiple: false - ), - _Value: Shape.TextBox( - Id: "value", Name: "Value", - Title: T("Value"), - Classes: new[] { "text medium", "tokenized" }, - Description: T("Enter the value the string should be.") - ) - ); + object form(IShapeFactory shape) { + var f = Shape.Form( + Id: "StringFilter", + _Operator: Shape.SelectList( + Id: "operator", Name: "Operator", + Title: T("Operator"), + Size: 1, + Multiple: false + ), + _Value: Shape.TextBox( + Id: "value", Name: "Value", + Title: T("Value"), + Classes: new[] { "text medium", "tokenized" }, + Description: T("Enter the value the string should be.") + ), + _IgnoreIfEmptyValue: Shape.Checkbox( + Id: "IgnoreFilterIfValueIsEmpty", + Name: "IgnoreFilterIfValueIsEmpty", + Title: T("Ignore filter if value is empty"), + Description: T("When enabled, the filter will not be applied if the provided value is or evaluates to empty."), + Value: "true" + )); - f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.Equals), Text = T("Is equal to").Text }); - f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.NotEquals), Text = T("Is not equal to").Text }); - f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.Contains), Text = T("Contains").Text }); - f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.ContainsAny), Text = T("Contains any word").Text }); - f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.ContainsAll), Text = T("Contains all words").Text }); - f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.Starts), Text = T("Starts with").Text }); - f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.NotStarts), Text = T("Does not start with").Text }); - f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.Ends), Text = T("Ends with").Text }); - f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.NotEnds), Text = T("Does not end with").Text }); - f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.NotContains), Text = T("Does not contain").Text }); + f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.Equals), Text = T("Is equal to").Text }); + f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.NotEquals), Text = T("Is not equal to").Text }); + f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.Contains), Text = T("Contains").Text }); + f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.ContainsAny), Text = T("Contains any word").Text }); + f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.ContainsAll), Text = T("Contains all words").Text }); + f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.Starts), Text = T("Starts with").Text }); + f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.NotStarts), Text = T("Does not start with").Text }); + f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.Ends), Text = T("Ends with").Text }); + f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.NotEnds), Text = T("Does not end with").Text }); + f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.NotContains), Text = T("Does not contain").Text }); - return f; - }; + return f; + } - context.Form(FormName, form); + context.Form(FormName, (Func)form); } @@ -61,6 +64,11 @@ public static Action GetFilterPredicate(dynamic formState var op = (StringOperator)Enum.Parse(typeof(StringOperator), Convert.ToString(formState.Operator)); object value = Convert.ToString(formState.Value); + if (bool.TryParse(formState.IgnoreFilterIfValueIsEmpty?.ToString() ?? "", out bool ignoreIfEmpty) + && ignoreIfEmpty + && string.IsNullOrWhiteSpace(value as string)) + return (ex) => { }; + switch (op) { case StringOperator.Equals: return x => x.Eq(property, value); @@ -134,6 +142,6 @@ public enum StringOperator { NotStarts, Ends, NotEnds, - NotContains, + NotContains } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Handlers/FieldIndexPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Projections/Handlers/FieldIndexPartHandler.cs index 12b3df9f2d0..fed0851a1b1 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Handlers/FieldIndexPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Handlers/FieldIndexPartHandler.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Orchard.ContentManagement; using Orchard.ContentManagement.Drivers; @@ -28,7 +29,7 @@ public FieldIndexPartHandler( _fieldIndexService = fieldIndexService; _fieldStorageProvider = fieldStorageProvider; _contentFieldDrivers = contentFieldDrivers; - + OnUpdated(Updated); OnPublishing(Publishing); } @@ -43,29 +44,62 @@ protected override void Activating(ActivatingContentContext context) { context.Builder.Weld(); } } + private void Updated(UpdateContentContext context, FieldIndexPart fieldIndexPart) { + // there are two different item types: saved in memory and saved to db + // those saved in memory don't have correctly the populated record and this generate NullReferenceException + if (context.UpdatingItemVersionRecord != null && context.UpdatingItemVersionRecord.Latest) { + // updates projection draft indexes only if it is the latest version + DescribeValuesToIndex(fieldIndexPart, (indexServiceContext) => { + _fieldIndexService.Set( + fieldIndexPart, + indexServiceContext.LocalPart.PartDefinition.Name, + indexServiceContext.LocalField.Name, + indexServiceContext.StorageName, indexServiceContext.FieldValue, indexServiceContext.StorageType, + FieldIndexRecordVersionOptions.LatestValue); + }); + } + } + public void Publishing(PublishContentContext context, FieldIndexPart fieldIndexPart) { + DescribeValuesToIndex(fieldIndexPart, (indexServiceContext) => { + _fieldIndexService.Set( + fieldIndexPart, + indexServiceContext.LocalPart.PartDefinition.Name, + indexServiceContext.LocalField.Name, + indexServiceContext.StorageName, indexServiceContext.FieldValue, indexServiceContext.StorageType); + + }); + } + /// + /// + /// + /// + /// + private void DescribeValuesToIndex(FieldIndexPart fieldIndexPart, Action indexService) { foreach (var part in fieldIndexPart.ContentItem.Parts) { - foreach(var field in part.PartDefinition.Fields) { - + foreach (var field in part.PartDefinition.Fields) { + // get all drivers for the current field type // the driver will describe what values of the field should be indexed var drivers = _contentFieldDrivers.Where(x => x.GetFieldInfo().Any(fi => fi.FieldTypeName == field.FieldDefinition.Name)).ToList(); - + ContentPart localPart = part; ContentPartFieldDefinition localField = field; - var membersContext = new DescribeMembersContext( + var membersContext = new DescribeMembersContext( (storageName, storageType, displayName, description) => { var fieldStorage = _fieldStorageProvider.BindStorage(localPart, localField); // fieldStorage.Get(storageName) var getter = typeof(IFieldStorage).GetMethod("Get").MakeGenericMethod(storageType); - var fieldValue = getter.Invoke(fieldStorage, new[] {storageName}); - - _fieldIndexService.Set(fieldIndexPart, - localPart.PartDefinition.Name, - localField.Name, - storageName, fieldValue, storageType); + var fieldValue = getter.Invoke(fieldStorage, new[] { storageName }); + indexService(new IndexServiceContext { + LocalPart = localPart, + LocalField = localField, + StorageName = storageName, + FieldValue = fieldValue, + StorageType = storageType + }); }); foreach (var driver in drivers) { @@ -74,5 +108,13 @@ public void Publishing(PublishContentContext context, FieldIndexPart fieldIndexP } } } + private class IndexServiceContext { + public ContentPart LocalPart { get; set; } + public ContentPartFieldDefinition LocalField { get; set; } + public string StorageName { get; set; } + public object FieldValue { get; set; } + public Type StorageType { get; set; } + + } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Migrations.cs b/src/Orchard.Web/Modules/Orchard.Projections/Migrations.cs index 149e8766794..982520d91a8 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Migrations.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Migrations.cs @@ -1,5 +1,6 @@ using System; using System.Data; +using System.Linq; using Orchard.ContentManagement.MetaData; using Orchard.Core.Common.Models; using Orchard.Core.Contents.Extensions; @@ -12,9 +13,29 @@ namespace Orchard.Projections { public class Migrations : DataMigrationImpl { private readonly IRepository _memberBindingRepository; - - public Migrations(IRepository memberBindingRepository) { + private readonly IRepository _layoutRepository; + private readonly IRepository _propertyRecordRepository; + private readonly IRepository _filterRepository; + + /// + /// When upgrading from "1.10.x" branch code committed after 1.10.3 to "dev" branch code or 1.11, merge + /// conflicts between "1.10.x" and "dev" caused by running the same migration steps in a different order need to + /// be resolved by instructing this migration to decide which steps need to be executed. If you're upgrading + /// under these conditions and your pre-upgrade migration version is 6, use HostComponents.config to override + /// this property to true. + /// + public bool IsUpgradingFromOrchard_1_10_x_Version_6 { get; set; } + + public Migrations( + IRepository memberBindingRepository, + IRepository layoutRepository, + IRepository propertyRecordRepository, + IRepository filterRepository) { _memberBindingRepository = memberBindingRepository; + _layoutRepository = layoutRepository; + _propertyRecordRepository = propertyRecordRepository; + _filterRepository = filterRepository; + T = NullLocalizer.Instance; } @@ -29,6 +50,7 @@ public int Create() { .Column("Id", c => c.PrimaryKey().Identity()) .Column("PropertyName") .Column("Value", c => c.WithLength(4000)) + .Column("LatestValue", c => c.WithLength(4000)) .Column("FieldIndexPartRecord_Id") ); @@ -37,6 +59,7 @@ public int Create() { .Column("Id", c => c.PrimaryKey().Identity()) .Column("PropertyName") .Column("Value") + .Column("LatestValue") .Column("FieldIndexPartRecord_Id") ); @@ -45,6 +68,7 @@ public int Create() { .Column("Id", c => c.PrimaryKey().Identity()) .Column("PropertyName") .Column("Value") + .Column("LatestValue") .Column("FieldIndexPartRecord_Id") ); @@ -53,11 +77,43 @@ public int Create() { .Column("Id", c => c.PrimaryKey().Identity()) .Column("PropertyName") .Column("Value") + .Column("LatestValue") .Column("FieldIndexPartRecord_Id") ); + //Adds indexes for better performances in queries + SchemaBuilder.AlterTable("StringFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_StringFieldIndexRecord", "FieldIndexPartRecord_Id"); + }); + SchemaBuilder.AlterTable("IntegerFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_IntegerFieldIndexRecord", "FieldIndexPartRecord_Id"); + }); + SchemaBuilder.AlterTable("DoubleFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_DoubleFieldIndexRecord", "FieldIndexPartRecord_Id"); + }); + SchemaBuilder.AlterTable("DecimalFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_DecimalFieldIndexRecords", "FieldIndexPartRecord_Id"); + }); + SchemaBuilder.CreateTable("FieldIndexPartRecord", table => table.ContentPartRecord()); + //Adds indexes for better performances in queries + SchemaBuilder.AlterTable("StringFieldIndexRecord", table => table.CreateIndex("IX_PropertyName", new string[] { "PropertyName" })); + SchemaBuilder.AlterTable("StringFieldIndexRecord", table => table.CreateIndex("IX_FieldIndexPartRecord_Id", new string[] { "FieldIndexPartRecord_Id" })); + + SchemaBuilder.AlterTable("IntegerFieldIndexRecord", table => table.CreateIndex("IX_PropertyName", new string[] { "PropertyName" })); + SchemaBuilder.AlterTable("IntegerFieldIndexRecord", table => table.CreateIndex("IX_FieldIndexPartRecord_Id", new string[] { "FieldIndexPartRecord_Id" })); + + SchemaBuilder.AlterTable("DoubleFieldIndexRecord", table => table.CreateIndex("IX_PropertyName", new string[] { "PropertyName" })); + SchemaBuilder.AlterTable("DoubleFieldIndexRecord", table => table.CreateIndex("IX_FieldIndexPartRecord_Id", new string[] { "FieldIndexPartRecord_Id" })); + + SchemaBuilder.AlterTable("DecimalFieldIndexRecord", table => table.CreateIndex("IX_PropertyName", new string[] { "PropertyName" })); + SchemaBuilder.AlterTable("DecimalFieldIndexRecord", table => table.CreateIndex("IX_FieldIndexPartRecord_Id", new string[] { "FieldIndexPartRecord_Id" })); + // Query ContentDefinitionManager.AlterTypeDefinition("Query", @@ -70,6 +126,7 @@ public int Create() { SchemaBuilder.CreateTable("QueryPartRecord", table => table .ContentPartRecord() + .Column("VersionScope", c => c.WithLength(15)) ); SchemaBuilder.CreateTable("FilterGroupRecord", @@ -108,6 +165,7 @@ public int Create() { .Column("Description", c => c.WithLength(255)) .Column("State", c => c.Unlimited()) .Column("DisplayType", c => c.WithLength(64)) + .Column("GUIdentifier", column => column.WithLength(68)) .Column("Display") .Column("QueryPartRecord_id") .Column("GroupProperty_id") @@ -143,6 +201,7 @@ public int Create() { .Column("HideEmpty") .Column("RewriteOutput") + .Column("RewriteOutputCondition", c => c.Unlimited()) .Column("RewriteText", c => c.Unlimited()) .Column("StripHtmlTags") .Column("TrimLength") @@ -196,9 +255,28 @@ public int Create() { .WithPart("ProjectionPart") .WithPart("AdminMenuPart", p => p.WithSetting("AdminMenuPartTypeSettings.DefaultPosition", "5")) .Creatable() + .Listable() .DisplayedAs("Projection") ); + SchemaBuilder.CreateTable("NavigationQueryPartRecord", + table => table.ContentPartRecord() + .Column("Items") + .Column("Skip") + .Column("QueryPartRecord_id") + ); + + ContentDefinitionManager.AlterTypeDefinition("NavigationQueryMenuItem", + cfg => cfg + .WithIdentity() + .WithPart("NavigationQueryPart") + .WithPart("MenuPart") + .WithPart("CommonPart") + .DisplayedAs("Query Link") + .WithSetting("Description", "Injects menu items from a Query") + .WithSetting("Stereotype", "MenuItem") + ); + // Default Model Bindings - CommonPartRecord _memberBindingRepository.Create(new MemberBindingRecord { @@ -240,7 +318,7 @@ public int Create() { Description = T("The text from the Body part").Text }); - return 1; + return 7; } public int UpdateFrom1() { @@ -263,7 +341,7 @@ public int UpdateFrom1() { ContentDefinitionManager.AlterTypeDefinition("ProjectionPage", cfg => cfg.Listable()); - return 3; + return 2; } public int UpdateFrom2() { @@ -282,5 +360,91 @@ public int UpdateFrom3() { return 4; } + + public int UpdateFrom4() { + SchemaBuilder.AlterTable("StringFieldIndexRecord", table => table + .AddColumn("LatestValue", c => c.WithLength(4000))); + + SchemaBuilder.AlterTable("IntegerFieldIndexRecord", table => table + .AddColumn("LatestValue")); + + SchemaBuilder.AlterTable("DoubleFieldIndexRecord", table => table + .AddColumn("LatestValue")); + + SchemaBuilder.AlterTable("DecimalFieldIndexRecord", table => table + .AddColumn("LatestValue")); + + //Adds indexes for better performances in queries + SchemaBuilder.AlterTable("StringFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_StringFieldIndexRecord", "FieldIndexPartRecord_Id"); + }); + SchemaBuilder.AlterTable("IntegerFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_IntegerFieldIndexRecord", "FieldIndexPartRecord_Id"); + }); + SchemaBuilder.AlterTable("DoubleFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_DoubleFieldIndexRecord", "FieldIndexPartRecord_Id"); + }); + SchemaBuilder.AlterTable("DecimalFieldIndexRecord", table => { + table.CreateIndex("IDX_Orchard_Projections_PropertyName", "PropertyName"); + table.CreateIndex("IDX_Orchard_Projections_DecimalFieldIndexRecords", "FieldIndexPartRecord_Id"); + }); + + SchemaBuilder.AlterTable("QueryPartRecord", table => table + .AddColumn("VersionScope", c => c.WithLength(15))); + + return 5; + } + + public int UpdateFrom5() { + MigratePropertyRecordToRewriteOutputCondition(); + + return 6; + } + + public int UpdateFrom6() { + // This change was originally UpdateFrom6 on 1.10.x and UpdateFrom6 on dev: Casting a somewhat wide net, but + // filters can't be queried by the form they are using and different types of filters can (and do) use + // StringFilterForm. However, the "Operator" parameter's value being "ContainsAnyIfProvided" is very + // specific. + var formStateToReplace = "ContainsAnyIfProvided"; + var filterRecordsToUpdate = _filterRepository.Table.Where(f => f.State.Contains(formStateToReplace)).ToList(); + foreach (var filter in filterRecordsToUpdate) { + filter.State = filter.State.Replace( + formStateToReplace, + "ContainsAnytrue"); + } + + if (IsUpgradingFromOrchard_1_10_x_Version_6) { + MigratePropertyRecordToRewriteOutputCondition(); + } + else { + // This change was originally UpdateFrom5 on 1.10.x and UpdateFrom6 on dev. + SchemaBuilder.AlterTable("LayoutRecord", table => + table.AddColumn("GUIdentifier", column => column.WithLength(68))); + + var layoutRecords = _layoutRepository.Table.Where(l => l.GUIdentifier == null || l.GUIdentifier == "").ToList(); + foreach (var layout in layoutRecords) { + layout.GUIdentifier = Guid.NewGuid().ToString(); + } + } + + return 7; + } + + // This change was originally in UpdateFrom5 on dev, but didn't exist on 1.10.x. + private void MigratePropertyRecordToRewriteOutputCondition() { + SchemaBuilder.AlterTable("PropertyRecord", table => table + .AddColumn("RewriteOutputCondition", c => c.Unlimited()) + ); + + foreach (var property in _propertyRecordRepository.Table) +#pragma warning disable CS0618 // Type or member is obsolete + // Reading this obsolete property to migrate its data to a new one. + if (property.RewriteOutput) property.RewriteOutputCondition = "true"; +#pragma warning restore CS0618 // Type or member is obsolete + } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Models/FieldIndexRecord.cs b/src/Orchard.Web/Modules/Orchard.Projections/Models/FieldIndexRecord.cs index 7b2b0332510..33c9de34a1e 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Models/FieldIndexRecord.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Models/FieldIndexRecord.cs @@ -1,6 +1,4 @@ -using System.ComponentModel.DataAnnotations; - -namespace Orchard.Projections.Models { +namespace Orchard.Projections.Models { public abstract class FieldIndexRecord { public virtual int Id { get; set; } public virtual string PropertyName { get; set; } @@ -8,18 +6,21 @@ public abstract class FieldIndexRecord { public class StringFieldIndexRecord : FieldIndexRecord { public virtual string Value { get; set; } + public virtual string LatestValue { get; set; } } public class IntegerFieldIndexRecord : FieldIndexRecord { public virtual long? Value { get; set; } + public virtual long? LatestValue { get; set; } } public class DoubleFieldIndexRecord : FieldIndexRecord { public virtual double? Value { get; set; } + public virtual double? LatestValue { get; set; } } public class DecimalFieldIndexRecord : FieldIndexRecord { public virtual decimal? Value { get; set; } + public virtual decimal? LatestValue { get; set; } } - } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Models/LayoutRecord.cs b/src/Orchard.Web/Modules/Orchard.Projections/Models/LayoutRecord.cs index 3f28c2ae703..9a249b41e99 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Models/LayoutRecord.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Models/LayoutRecord.cs @@ -9,9 +9,11 @@ public LayoutRecord() { } public virtual int Id { get; set; } + public virtual string GUIdentifier { get; set; } public virtual string Description { get; set; } public virtual string Category { get; set; } public virtual string Type { get; set; } + [StringLengthMax] public virtual string State { get; set; } public virtual int Display { get; set; } diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Models/PropertyRecord.cs b/src/Orchard.Web/Modules/Orchard.Projections/Models/PropertyRecord.cs index a3a83150e80..843ced4c270 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Models/PropertyRecord.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Models/PropertyRecord.cs @@ -1,4 +1,5 @@ -using System.ComponentModel.DataAnnotations; +using System; +using System.ComponentModel.DataAnnotations; namespace Orchard.Projections.Models { public class PropertyRecord { @@ -42,7 +43,9 @@ public class PropertyRecord { public virtual bool HideEmpty { get; set; } // Rewrite Result + [Obsolete("Set RewriteOutputCondition to \"true\" instead.")] public virtual bool RewriteOutput { get; set; } + public virtual string RewriteOutputCondition { get; set; } public virtual string RewriteText { get; set; } public virtual bool StripHtmlTags { get; set; } public virtual bool TrimLength { get; set; } diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Models/QueryPart.cs b/src/Orchard.Web/Modules/Orchard.Projections/Models/QueryPart.cs index f085c59e165..0b0c920e74c 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Models/QueryPart.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Models/QueryPart.cs @@ -6,10 +6,14 @@ namespace Orchard.Projections.Models { public class QueryPart : ContentPart { public string Name { - get { return this.As().Title; } + get { return this.As().Title; } set { this.As().Title = value; } } + public QueryVersionScopeOptions VersionScope { + get { return Retrieve(x => x.VersionScope); } + set { Store(x => x.VersionScope, value); } + } public IList SortCriteria { get { return Record.SortCriteria; } } diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Models/QueryPartRecord.cs b/src/Orchard.Web/Modules/Orchard.Projections/Models/QueryPartRecord.cs index a295f18afed..09f6ff21437 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Models/QueryPartRecord.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Models/QueryPartRecord.cs @@ -6,11 +6,14 @@ namespace Orchard.Projections.Models { public class QueryPartRecord : ContentPartRecord { public QueryPartRecord() { + VersionScope = QueryVersionScopeOptions.Published; FilterGroups = new List(); SortCriteria = new List(); Layouts = new List(); } + public virtual QueryVersionScopeOptions VersionScope { get; set; } + [CascadeAllDeleteOrphan, Aggregate] [XmlArray("FilterGroupRecords")] public virtual IList FilterGroups { get; set; } @@ -22,6 +25,5 @@ public QueryPartRecord() { [CascadeAllDeleteOrphan, Aggregate] [XmlArray("Layouts")] public virtual IList Layouts { get; set; } - } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Models/QueryVersionScopeOptions.cs b/src/Orchard.Web/Modules/Orchard.Projections/Models/QueryVersionScopeOptions.cs new file mode 100644 index 00000000000..b0812dce2fe --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Projections/Models/QueryVersionScopeOptions.cs @@ -0,0 +1,7 @@ +namespace Orchard.Projections.Models { + public enum QueryVersionScopeOptions { + Published, + Latest, + Draft + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Module.txt b/src/Orchard.Web/Modules/Orchard.Projections/Module.txt index 479515161a6..12ba65b98ee 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Projections/Module.txt @@ -2,8 +2,8 @@ Name: Projector AntiForgery: enabled Author: The Orchard Team Website: http://www.orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Provides methods to control how lists of content items are filtered and displayed Category: Content -Dependencies: Orchard.Tokens, Orchard.Forms, Feeds, Title +Dependencies: Orchard.Tokens, Orchard.Conditions, Orchard.Forms, Feeds, Title diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Orchard.Projections.csproj b/src/Orchard.Web/Modules/Orchard.Projections/Orchard.Projections.csproj index 003e87bd91c..2ef8e50c540 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Orchard.Projections.csproj +++ b/src/Orchard.Web/Modules/Orchard.Projections/Orchard.Projections.csproj @@ -12,8 +12,8 @@ Properties Orchard.Projections Orchard.Projections - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -26,6 +26,9 @@ + + + true @@ -49,18 +52,27 @@ false - - ..\..\..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll - True + + ..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll + + + ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll + + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - - ..\..\..\packages\NHibernate.4.0.1.4000\lib\net40\NHibernate.dll - True + + ..\..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll + + + ..\..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll + + + ..\..\..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll @@ -69,6 +81,8 @@ + + @@ -76,29 +90,23 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -124,6 +132,8 @@ + + @@ -132,12 +142,20 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) + + + {0E7646E8-FE8F-43C1-8799-D97860925EC4} + Orchard.ContentTypes + + + {98251EAE-A41B-47B2-AA91-E28B8482DA70} + Orchard.Conditions {642A49D7-8752-4177-80D6-BFBBCFAD3DE0} @@ -166,6 +184,8 @@ + + @@ -175,7 +195,9 @@ - + + + @@ -278,6 +300,7 @@ + @@ -319,7 +342,11 @@ - + + + + + 10.0 @@ -345,7 +372,7 @@ --> - + @@ -359,7 +386,7 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Placement.info b/src/Orchard.Web/Modules/Orchard.Projections/Placement.info index 96b4df8d970..42174c424ef 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Placement.info +++ b/src/Orchard.Web/Modules/Orchard.Projections/Placement.info @@ -5,7 +5,7 @@ - + diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Projections/Properties/AssemblyInfo.cs index 3858d071afa..206f43822cc 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Builders/MemberBindingsStep.cs b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Builders/MemberBindingsStep.cs new file mode 100644 index 00000000000..c4950622998 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Builders/MemberBindingsStep.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using Orchard.Data; +using Orchard.Localization; +using Orchard.Projections.Services; +using Orchard.Recipes.Services; + +namespace Orchard.Projections.Providers.Builders { + public class MemberBindingsStep : RecipeBuilderStep { + private readonly IMemberBindingProvider _memberBindingProvider; + public MemberBindingsStep(IMemberBindingProvider memberBindingProvider) { + _memberBindingProvider = memberBindingProvider; + } + + public override string Name { + get { return "MemberBindings"; } + } + + public override LocalizedString DisplayName { + get { return T("Member Bindings"); } + } + + public override LocalizedString Description { + get { return T("Exports query member bindings."); } + } + + public override int Priority { + get { return 25; } + } + + public override int Position { + get { return 25; } + } + + public override void Build(BuildContext context) { + var memberBindings = new XElement("MemberBindings"); + context.RecipeDocument.Element("Orchard").Add(memberBindings); + + var bindingBuilder = new BindingBuilder(); + _memberBindingProvider.GetMemberBindings(bindingBuilder); + + foreach (var bindingItem in bindingBuilder.Build()) { + var declaringType = bindingItem.Property.DeclaringType; + + var memberBinding = new XElement("MemberBinding", + new XAttribute("Type", declaringType.FullName), + new XAttribute("Member", bindingItem.Property.Name), + new XAttribute("Description", bindingItem.Description), + new XAttribute("DisplayName", bindingItem.DisplayName)); + + memberBindings.Add(memberBinding); + } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Executors/MemberBindingsStep.cs b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Executors/MemberBindingsStep.cs new file mode 100644 index 00000000000..645376b41be --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Executors/MemberBindingsStep.cs @@ -0,0 +1,42 @@ +using System; +using Orchard.Data; +using Orchard.Logging; +using Orchard.Projections.Models; +using Orchard.Recipes.Models; +using Orchard.Recipes.Services; + +namespace Orchard.Projections.Providers.Executors { + public class MemberBindingsStep : RecipeExecutionStep { + private readonly IRepository _repository; + + public MemberBindingsStep(IRepository repository, RecipeExecutionLogger logger) : base(logger) { + _repository = repository; + } + + public override string Name { + get { return "MemberBindings"; } + } + + public override void Execute(RecipeExecutionContext context) { + foreach (var memberBindingElement in context.RecipeStep.Step.Elements()) { + Logger.Information("Importing member bindings."); + try { + var member = memberBindingElement.Attribute("Member").Value; + var type = memberBindingElement.Attribute("Type").Value; + if (_repository.Get(b => b.Member == member && b.Type == type) != null) + continue; + _repository.Create(new MemberBindingRecord { + Member = member, + Type = type, + DisplayName = memberBindingElement.Attribute("DisplayName").Value, + Description = memberBindingElement.Attribute("Description").Value, + }); + } + catch (Exception ex) { + Logger.Error(ex, "Error while importing member bindings."); + throw; + } + } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Filters/ContentFieldsFilter.cs b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Filters/ContentFieldsFilter.cs index d9703e30bfa..98cd0910e66 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Filters/ContentFieldsFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Filters/ContentFieldsFilter.cs @@ -75,7 +75,9 @@ public void ApplyFilter(FilterContext context, IFieldTypeEditor fieldTypeEditor, var relationship = fieldTypeEditor.GetFilterRelationship(propertyName.ToSafeName()); // generate the predicate based on the editor which has been used - Action predicate = fieldTypeEditor.GetFilterPredicate(context.State); + dynamic fullState = context.State; + fullState.VersionScope = context.QueryPartRecord.VersionScope; + Action predicate = fieldTypeEditor.GetFilterPredicate(fullState); // combines the predicate with a filter on the specific property name of the storage, as implemented in FieldIndexService Action andPredicate = x => x.And(y => y.Eq("PropertyName", propertyName), predicate); diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/GridLayoutForms.cs b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/GridLayoutForms.cs index ad39693338e..f9f7a7b512a 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/GridLayoutForms.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/GridLayoutForms.cs @@ -86,7 +86,7 @@ public void Describe(DescribeContext context) { Description: T("The class to provide on each cell."), Classes: new[] { "text medium", "tokenized" } ), - _EmptyCell: Shape.TextBox( + _EmptyCell: Shape.TextArea( Id: "empty-cell", Name: "EmptyCell", Title: T("Empty Cell"), Description: T("The HTML to render as empty cells to fill a row. (e.g.,  )"), @@ -103,7 +103,7 @@ public void Describe(DescribeContext context) { } } - public class GridLayoutFormsValitator : FormHandler { + public class GridLayoutFormsValidator : FormHandler { public Localizer T { get; set; } public override void Validating(ValidatingContext context) { diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/ListLayoutForms.cs b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/ListLayoutForms.cs index f3abf691473..9848659e287 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/ListLayoutForms.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/ListLayoutForms.cs @@ -65,7 +65,7 @@ public void Describe(DescribeContext context) { } } - public class ListLayoutFormsValitator : FormHandler { + public class ListLayoutFormsValidator : FormHandler { public Localizer T { get; set; } public override void Validating(ValidatingContext context) { diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/RawLayoutForms.cs b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/RawLayoutForms.cs index d2aaf653533..393b485827a 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/RawLayoutForms.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Providers/Layouts/RawLayoutForms.cs @@ -53,19 +53,19 @@ public void Describe(DescribeContext context) { Description: T("The class to provide on each item."), Classes: new[] { "text medium", "tokenized" } ), - _Prepend: Shape.TextBox( + _Prepend: Shape.TextArea( Id: "prepend", Name: "Prepend", Title: T("Prepend"), Description: T("Some HTML to insert before the first element."), Classes: new[] { "text medium", "tokenized" } ), - _Separator: Shape.TextBox( + _Separator: Shape.TextArea( Id: "separator", Name: "Separator", Title: T("Separator"), Description: T("Some HTML to insert between two items."), Classes: new[] { "text medium", "tokenized" } ), - _Append: Shape.TextBox( + _Append: Shape.TextArea( Id: "append", Name: "Append", Title: T("Append"), Description: T("Some HTML to insert after the last element."), diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Providers/SortCriteria/ContentFieldsSortCriteria.cs b/src/Orchard.Web/Modules/Orchard.Projections/Providers/SortCriteria/ContentFieldsSortCriteria.cs index 20eb1ac7eec..05ef6cd0d90 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Providers/SortCriteria/ContentFieldsSortCriteria.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Providers/SortCriteria/ContentFieldsSortCriteria.cs @@ -32,14 +32,14 @@ public ContentFieldsSortCriterion( public Localizer T { get; set; } public void Describe(DescribeSortCriterionContext describe) { - foreach(var part in _contentDefinitionManager.ListPartDefinitions()) { - if(!part.Fields.Any()) { + foreach (var part in _contentDefinitionManager.ListPartDefinitions()) { + if (!part.Fields.Any()) { continue; } var descriptor = describe.For(part.Name + "ContentFields", T("{0} Content Fields", part.Name.CamelFriendly()), T("Content Fields for {0}", part.Name.CamelFriendly())); - foreach(var field in part.Fields) { + foreach (var field in part.Fields) { var localField = field; var localPart = part; var drivers = _contentFieldDrivers.Where(x => x.GetFieldInfo().Any(fi => fi.FieldTypeName == localField.FieldDefinition.Name)).ToList(); @@ -57,8 +57,8 @@ public void Describe(DescribeSortCriterionContext describe) { display: context => DisplaySortCriterion(context, localPart, localField), form: SortCriterionFormProvider.FormName); }); - - foreach(var driver in drivers) { + + foreach (var driver in drivers) { driver.Describe(membersContext); } } @@ -79,11 +79,11 @@ public void ApplySortCriterion(SortCriterionContext context, IFieldTypeEditor fi // apply where clause context.Query = context.Query.Where(relationship, predicate); - + // apply sort - context.Query = ascending - ? context.Query.OrderBy(relationship, x => x.Asc("Value")) - : context.Query.OrderBy(relationship, x => x.Desc("Value")); + context.Query = ascending + ? context.Query.OrderBy(relationship, x => x.Asc(context.GetSortColumnName())) + : context.Query.OrderBy(relationship, x => x.Desc(context.GetSortColumnName())); } public LocalizedString DisplaySortCriterion(SortCriterionContext context, ContentPartDefinition part, ContentPartFieldDefinition fieldDefinition) { diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Providers/SortCriteria/SortOrderFormProvider.cs b/src/Orchard.Web/Modules/Orchard.Projections/Providers/SortCriteria/SortOrderFormProvider.cs index ef002b192e3..cea1aaefcde 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Providers/SortCriteria/SortOrderFormProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Providers/SortCriteria/SortOrderFormProvider.cs @@ -42,7 +42,7 @@ public void Describe(DescribeContext context) { } } - public class SortCriterionFormValitator : FormHandler { + public class SortCriterionFormValidator : FormHandler { public Localizer T { get; set; } public override void Validating(ValidatingContext context) { diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Scripts/datetime-editor-filter.js b/src/Orchard.Web/Modules/Orchard.Projections/Scripts/datetime-editor-filter.js index b4644f35626..55fe958a839 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Scripts/datetime-editor-filter.js +++ b/src/Orchard.Web/Modules/Orchard.Projections/Scripts/datetime-editor-filter.js @@ -2,16 +2,30 @@ // show/hide Min/Max fields $("#operator option:selected").each(function () { var val = $(this).val(); - if (val == 'Between' || val == 'NotBetween') { + + if (val == 'IsNull' || val == 'IsNotNull') { + $('#value-type-date').closest('div').hide(); + $('#value-type-timespan').closest('div').hide(); + $('#fieldset-single').hide(); - $('#fieldset-min').show(); - $('#fieldset-max').show(); - } - else { - $('#fieldset-single').show(); $('#fieldset-min').hide(); $('#fieldset-max').hide(); } + else { + $('#value-type-date').closest('div').show(); + $('#value-type-timespan').closest('div').show(); + + if (val == 'Between' || val == 'NotBetween') { + $('#fieldset-single').hide(); + $('#fieldset-min').show(); + $('#fieldset-max').show(); + } + else { + $('#fieldset-single').show(); + $('#fieldset-min').hide(); + $('#fieldset-max').hide(); + } + } }); // show/hide unit selectors diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Services/CustomMemberBindingProvider.cs b/src/Orchard.Web/Modules/Orchard.Projections/Services/CustomMemberBindingProvider.cs index 5b28d941e09..20c35d24b4f 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Services/CustomMemberBindingProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Services/CustomMemberBindingProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; using Orchard.Data; @@ -16,11 +17,18 @@ public CustomMemberBindingProvider( _sessionFactoryHolder = sessionFactoryHolder; } + private List memberBindings; public void GetMemberBindings(BindingBuilder builder) { var recordBluePrints = _sessionFactoryHolder.GetSessionFactoryParameters().RecordDescriptors; - foreach(var member in _repository.Table.ToList()) { + // save this in memory once per request, to avoid hitting the database 5+ + // times per projection per request. + if (memberBindings == null) { + memberBindings = _repository.Table.ToList(); + } + + foreach (var member in memberBindings) { var record = recordBluePrints.FirstOrDefault(r => String.Equals(r.Type.FullName, member.Type, StringComparison.OrdinalIgnoreCase)); if (record == null) { @@ -28,7 +36,7 @@ public void GetMemberBindings(BindingBuilder builder) { } var property = record.Type.GetProperty(member.Member, BindingFlags.Instance | BindingFlags.Public); - if(property == null) { + if (property == null) { continue; } diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Services/FieldIndexService.cs b/src/Orchard.Web/Modules/Orchard.Projections/Services/FieldIndexService.cs index ec7df024370..f712e60d16a 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Services/FieldIndexService.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Services/FieldIndexService.cs @@ -5,12 +5,16 @@ namespace Orchard.Projections.Services { public class FieldIndexService : IFieldIndexService { - public void Set(FieldIndexPart part, string partName, string fieldName, string valueName, object value, Type valueType) { - var propertyName = String.Join(".", partName, fieldName, valueName ?? ""); + public void Set(FieldIndexPart part, string partName, string fieldName, string valueName, object value, Type valueType) => + Set(part, partName, fieldName, valueName, value, valueType, FieldIndexRecordVersionOptions.Value); + + public void Set(FieldIndexPart part, string partName, string fieldName, string valueName, object value, Type valueType, + FieldIndexRecordVersionOptions fieldIndexRecordVersionOption) { + var propertyName = string.Join(".", partName, fieldName, valueName ?? ""); var typeCode = Type.GetTypeCode(valueType); - if(valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Nullable<>)) { + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Nullable<>)) { typeCode = Type.GetTypeCode(Nullable.GetUnderlyingType(valueType)); } @@ -23,10 +27,19 @@ public void Set(FieldIndexPart part, string partName, string fieldName, string v part.Record.StringFieldIndexRecords.Add(stringRecord); } - // take the first 4000 chars as it is the limit for the field - stringRecord.Value = value == null ? null : value.ToString().Substring(0, Math.Min(value.ToString().Length, 4000)); + // Take the first 4000 chars as it is the limit for the field. + var stringRecordValue = value?.ToString().Substring(0, Math.Min(value.ToString().Length, 4000)); + switch (fieldIndexRecordVersionOption) { + case FieldIndexRecordVersionOptions.Value: + stringRecord.Value = stringRecordValue; + + break; + case FieldIndexRecordVersionOptions.LatestValue: + stringRecord.LatestValue = stringRecordValue; + + break; + } - break; case TypeCode.Byte: case TypeCode.SByte: @@ -42,7 +55,18 @@ public void Set(FieldIndexPart part, string partName, string fieldName, string v part.Record.IntegerFieldIndexRecords.Add(integerRecord); } - integerRecord.Value = value == null ? default(long?) : Convert.ToInt64(value); + var integerRecordValue = value == null ? default(long?) : Convert.ToInt64(value); + switch (fieldIndexRecordVersionOption) { + case FieldIndexRecordVersionOptions.Value: + integerRecord.Value = integerRecordValue; + + break; + case FieldIndexRecordVersionOptions.LatestValue: + integerRecord.LatestValue = integerRecordValue; + + break; + } + break; case TypeCode.DateTime: var dateTimeRecord = part.Record.IntegerFieldIndexRecords.FirstOrDefault(r => r.PropertyName == propertyName); @@ -51,7 +75,18 @@ public void Set(FieldIndexPart part, string partName, string fieldName, string v part.Record.IntegerFieldIndexRecords.Add(dateTimeRecord); } - dateTimeRecord.Value = value == null ? default(long?) : ((DateTime)value).Ticks; + var dateTimeRecordValue = value == null ? default(long?) : ((DateTime)value).Ticks; + switch (fieldIndexRecordVersionOption) { + case FieldIndexRecordVersionOptions.Value: + dateTimeRecord.Value = dateTimeRecordValue; + + break; + case FieldIndexRecordVersionOptions.LatestValue: + dateTimeRecord.LatestValue = dateTimeRecordValue; + + break; + } + break; case TypeCode.Boolean: var booleanRecord = part.Record.IntegerFieldIndexRecords.FirstOrDefault(r => r.PropertyName == propertyName); @@ -60,7 +95,18 @@ public void Set(FieldIndexPart part, string partName, string fieldName, string v part.Record.IntegerFieldIndexRecords.Add(booleanRecord); } - booleanRecord.Value = value == null ? default(long?) : Convert.ToInt64((bool)value); + var booleanRecordValue = value == null ? default(long?) : Convert.ToInt64((bool)value); + switch (fieldIndexRecordVersionOption) { + case FieldIndexRecordVersionOptions.Value: + booleanRecord.Value = booleanRecordValue; + + break; + case FieldIndexRecordVersionOptions.LatestValue: + booleanRecord.LatestValue = booleanRecordValue; + + break; + } + break; case TypeCode.Decimal: var decimalRecord = part.Record.DecimalFieldIndexRecords.FirstOrDefault(r => r.PropertyName == propertyName); @@ -69,7 +115,18 @@ public void Set(FieldIndexPart part, string partName, string fieldName, string v part.Record.DecimalFieldIndexRecords.Add(decimalRecord); } - decimalRecord.Value = value == null ? default(decimal?) : Convert.ToDecimal((decimal)value); + var decimalRecordValue = value == null ? default(decimal?) : Convert.ToDecimal((decimal)value); + switch (fieldIndexRecordVersionOption) { + case FieldIndexRecordVersionOptions.Value: + decimalRecord.Value = decimalRecordValue; + + break; + case FieldIndexRecordVersionOptions.LatestValue: + decimalRecord.LatestValue = decimalRecordValue; + + break; + } + break; case TypeCode.Single: case TypeCode.Double: @@ -79,13 +136,27 @@ public void Set(FieldIndexPart part, string partName, string fieldName, string v part.Record.DoubleFieldIndexRecords.Add(doubleRecord); } - doubleRecord.Value = value == null ? default(double?) : Convert.ToDouble(value); + var doubleRecordValue = value == null ? default(double?) : Convert.ToDouble(value); + switch (fieldIndexRecordVersionOption) { + case FieldIndexRecordVersionOptions.Value: + doubleRecord.Value = doubleRecordValue; + + break; + case FieldIndexRecordVersionOptions.LatestValue: + doubleRecord.LatestValue = doubleRecordValue; + + break; + } + break; } } - public T Get(FieldIndexPart part, string partName, string fieldName, string valueName) { - var propertyName = String.Join(".", partName, fieldName, valueName ?? ""); + public T Get(FieldIndexPart part, string partName, string fieldName, string valueName) => + Get(part, partName, fieldName, valueName, FieldIndexRecordVersionOptions.Value); + + public T Get(FieldIndexPart part, string partName, string fieldName, string valueName, FieldIndexRecordVersionOptions fieldIndexRecordVersionOption) { + var propertyName = string.Join(".", partName, fieldName, valueName ?? ""); var typeCode = Type.GetTypeCode(typeof(T)); @@ -93,7 +164,20 @@ public T Get(FieldIndexPart part, string partName, string fieldName, string v case TypeCode.Char: case TypeCode.String: var stringRecord = part.Record.StringFieldIndexRecords.FirstOrDefault(r => r.PropertyName == propertyName); - return stringRecord != null ? (T)Convert.ChangeType(stringRecord.Value, typeof(T)) : default(T); + var stringRecordValue = default(T); + + switch (fieldIndexRecordVersionOption) { + case FieldIndexRecordVersionOptions.Value: + stringRecordValue = (T)Convert.ChangeType(stringRecord.Value, typeof(T)); + + break; + case FieldIndexRecordVersionOptions.LatestValue: + stringRecordValue = (T)Convert.ChangeType(stringRecord.LatestValue, typeof(T)); + + break; + } + + return stringRecord != null ? stringRecordValue : default; case TypeCode.Byte: case TypeCode.SByte: case TypeCode.Int16: @@ -103,22 +187,87 @@ public T Get(FieldIndexPart part, string partName, string fieldName, string v case TypeCode.UInt32: case TypeCode.UInt64: var integerRecord = part.Record.IntegerFieldIndexRecords.FirstOrDefault(r => r.PropertyName == propertyName); - return integerRecord != null ? (T)Convert.ChangeType(integerRecord.Value, typeof(T)) : default(T); + var integerRecordValue = default(T); + + switch (fieldIndexRecordVersionOption) { + case FieldIndexRecordVersionOptions.Value: + integerRecordValue = (T)Convert.ChangeType(integerRecord.Value, typeof(T)); + + break; + case FieldIndexRecordVersionOptions.LatestValue: + integerRecordValue = (T)Convert.ChangeType(integerRecord.LatestValue, typeof(T)); + + break; + } + + return integerRecord != null ? integerRecordValue : default; case TypeCode.Decimal: var decimalRecord = part.Record.DecimalFieldIndexRecords.FirstOrDefault(r => r.PropertyName == propertyName); - return decimalRecord != null ? (T)Convert.ChangeType(decimalRecord.Value, typeof(T)) : default(T); + var decimalRecordValue = default(T); + + switch (fieldIndexRecordVersionOption) { + case FieldIndexRecordVersionOptions.Value: + decimalRecordValue = (T)Convert.ChangeType(decimalRecord.Value, typeof(T)); + + break; + case FieldIndexRecordVersionOptions.LatestValue: + decimalRecordValue = (T)Convert.ChangeType(decimalRecord.LatestValue, typeof(T)); + + break; + } + + return decimalRecord != null ? decimalRecordValue : default; case TypeCode.Single: case TypeCode.Double: var doubleRecord = part.Record.DoubleFieldIndexRecords.FirstOrDefault(r => r.PropertyName == propertyName); - return doubleRecord != null ? (T)Convert.ChangeType(doubleRecord.Value, typeof(T)) : default(T); + var doubleRecordValue = default(T); + + switch (fieldIndexRecordVersionOption) { + case FieldIndexRecordVersionOptions.Value: + doubleRecordValue = (T)Convert.ChangeType(doubleRecord.Value, typeof(T)); + + break; + case FieldIndexRecordVersionOptions.LatestValue: + doubleRecordValue = (T)Convert.ChangeType(doubleRecord.LatestValue, typeof(T)); + + break; + } + + return doubleRecord != null ? doubleRecordValue : default; case TypeCode.DateTime: var dateTimeRecord = part.Record.IntegerFieldIndexRecords.FirstOrDefault(r => r.PropertyName == propertyName); - return dateTimeRecord != null ? (T)Convert.ChangeType(new DateTime(Convert.ToInt64(dateTimeRecord.Value)), typeof(T)) : default(T); + var dateTimeRecordValue = default(T); + + switch (fieldIndexRecordVersionOption) { + case FieldIndexRecordVersionOptions.Value: + dateTimeRecordValue = (T)Convert.ChangeType(new DateTime(Convert.ToInt64(dateTimeRecord.Value)), typeof(T)); + + break; + case FieldIndexRecordVersionOptions.LatestValue: + dateTimeRecordValue = (T)Convert.ChangeType(new DateTime(Convert.ToInt64(dateTimeRecord.LatestValue)), typeof(T)); + + break; + } + + return dateTimeRecord != null ? dateTimeRecordValue : default; case TypeCode.Boolean: var booleanRecord = part.Record.IntegerFieldIndexRecords.FirstOrDefault(r => r.PropertyName == propertyName); - return booleanRecord != null ? (T)Convert.ChangeType(booleanRecord.Value, typeof(T)) : default(T); + var booleanRecordValue = default(T); + + switch (fieldIndexRecordVersionOption) { + case FieldIndexRecordVersionOptions.Value: + booleanRecordValue = (T)Convert.ChangeType(booleanRecord.Value, typeof(T)); + + break; + case FieldIndexRecordVersionOptions.LatestValue: + booleanRecordValue = (T)Convert.ChangeType(booleanRecord.LatestValue, typeof(T)); + + break; + } + + return booleanRecord != null ? booleanRecordValue : default; default: - return default(T); + return default; } } } diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Services/IFieldIndexService.cs b/src/Orchard.Web/Modules/Orchard.Projections/Services/IFieldIndexService.cs index e5019809577..66283a22282 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Services/IFieldIndexService.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Services/IFieldIndexService.cs @@ -3,7 +3,14 @@ namespace Orchard.Projections.Services { public interface IFieldIndexService : IDependency { - void Set(FieldIndexPart part, string partName, string fieldName, string valueName, object value, Type valueType); T Get(FieldIndexPart part, string partName, string fieldName, string valueName); + T Get(FieldIndexPart part, string partName, string fieldName, string valueName, FieldIndexRecordVersionOptions fieldIndexRecordVersionOption); + void Set(FieldIndexPart part, string partName, string fieldName, string valueName, object value, Type valueType); + void Set(FieldIndexPart part, string partName, string fieldName, string valueName, object value, Type valueType, FieldIndexRecordVersionOptions fieldIndexRecordVersionOption); + } + + public enum FieldIndexRecordVersionOptions { + Value, + LatestValue } } diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Services/IProjectionManager.cs b/src/Orchard.Web/Modules/Orchard.Projections/Services/IProjectionManager.cs index a07f480bdcf..9915331d00a 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Services/IProjectionManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Services/IProjectionManager.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using Orchard.ContentManagement; using Orchard.Projections.Descriptors; -using Orchard.Projections.Descriptors.Property; using Orchard.Projections.Descriptors.Filter; using Orchard.Projections.Descriptors.Layout; +using Orchard.Projections.Descriptors.Property; using Orchard.Projections.Descriptors.SortCriterion; namespace Orchard.Projections.Services { @@ -19,7 +19,9 @@ public interface IProjectionManager : IDependency { PropertyDescriptor GetProperty(string category, string type); IEnumerable GetContentItems(int queryId, int skip = 0, int count = 0); + IEnumerable GetContentItems(int queryId, ContentPart part, int skip = 0, int count = 0); + int GetCount(int queryId); + int GetCount(int queryId, ContentPart part); } - } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Services/IProjectionManagerExtension.cs b/src/Orchard.Web/Modules/Orchard.Projections/Services/IProjectionManagerExtension.cs deleted file mode 100644 index cad06b62eea..00000000000 --- a/src/Orchard.Web/Modules/Orchard.Projections/Services/IProjectionManagerExtension.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; -using Orchard.ContentManagement; -using Orchard.Projections.Descriptors; -using Orchard.Projections.Descriptors.Property; -using Orchard.Projections.Descriptors.Filter; -using Orchard.Projections.Descriptors.Layout; -using Orchard.Projections.Descriptors.SortCriterion; - -namespace Orchard.Projections.Services { - public interface IProjectionManagerExtension : IProjectionManager { - - IEnumerable GetContentItems(int queryId, ContentPart part, int skip = 0, int count = 0); - int GetCount(int queryId, ContentPart part); - } - -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Services/ProjectionManager.cs b/src/Orchard.Web/Modules/Orchard.Projections/Services/ProjectionManager.cs index 69e343132ce..f579c3e4466 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Services/ProjectionManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Services/ProjectionManager.cs @@ -4,17 +4,17 @@ using Orchard.ContentManagement; using Orchard.Data; using Orchard.Forms.Services; -using Orchard.Projections.Descriptors; using Orchard.Localization; -using Orchard.Projections.Descriptors.Property; +using Orchard.Projections.Descriptors; using Orchard.Projections.Descriptors.Filter; using Orchard.Projections.Descriptors.Layout; +using Orchard.Projections.Descriptors.Property; using Orchard.Projections.Descriptors.SortCriterion; using Orchard.Projections.Models; using Orchard.Tokens; namespace Orchard.Projections.Services { - public class ProjectionManager : IProjectionManagerExtension { + public class ProjectionManager : IProjectionManager { private readonly ITokenizer _tokenizer; private readonly IEnumerable _filterProviders; private readonly IEnumerable _sortCriterionProviders; @@ -120,9 +120,11 @@ public int GetCount(int queryId, ContentPart part) { tokens.Add("Content", part.ContentItem); } - // aggregate the result for each group query - return GetContentQueries(queryRecord, Enumerable.Empty(), tokens) - .Sum(contentQuery => contentQuery.Count()); + var contentQueries = GetContentQueries(queryRecord, Enumerable.Empty(), tokens); + + return queryRecord.FilterGroups.Count > 1 ? + contentQueries.SelectMany(contentQuery => contentQuery.ListIds()).Distinct().Count() : + contentQueries.Sum(contentQuery => contentQuery.Count()); } public IEnumerable GetContentItems(int queryId, int skip = 0, int count = 0) { @@ -166,9 +168,12 @@ public IEnumerable GetContentItems(int queryId, ContentPart part, i // iterate over each sort criteria to apply the alterations to the query object foreach (var sortCriterion in queryRecord.SortCriteria.OrderBy(s => s.Position)) { + var tokenizedState = _tokenizer.Replace(sortCriterion.State, tokens); var sortCriterionContext = new SortCriterionContext { Query = groupQuery, - State = FormParametersHelper.ToDynamic(sortCriterion.State) + State = FormParametersHelper.ToDynamic(tokenizedState), + QueryPartRecord = queryRecord, + Tokens = tokens }; string category = sortCriterion.Category; @@ -188,7 +193,7 @@ public IEnumerable GetContentItems(int queryId, ContentPart part, i groupQuery = sortCriterionContext.Query; } - return groupQuery.Slice(skip, count); + return groupQuery.Slice(0, count); } public IEnumerable GetContentQueries(QueryPartRecord queryRecord, IEnumerable sortCriteria, Dictionary tokens) { @@ -199,17 +204,20 @@ public IEnumerable GetContentQueries(QueryPartRecord queryRecord, IEn tokens = new Dictionary(); } - // pre-executing all groups - foreach (var group in queryRecord.FilterGroups) { + var version = queryRecord.VersionScope.ToVersionOptions(); - var contentQuery = _contentManager.HqlQuery().ForVersion(VersionOptions.Published); + // pre-executing all groups + foreach (var group in queryRecord.FilterGroups) { + var contentQuery = _contentManager.HqlQuery().ForVersion(version); // iterate over each filter to apply the alterations to the query object foreach (var filter in group.Filters) { var tokenizedState = _tokenizer.Replace(filter.State, tokens); var filterContext = new FilterContext { Query = contentQuery, - State = FormParametersHelper.ToDynamic(tokenizedState) + State = FormParametersHelper.ToDynamic(tokenizedState), + QueryPartRecord = queryRecord, + Tokens = tokens }; string category = filter.Category; @@ -233,9 +241,12 @@ public IEnumerable GetContentQueries(QueryPartRecord queryRecord, IEn // iterate over each sort criteria to apply the alterations to the query object foreach (var sortCriterion in sortCriteria.OrderBy(s => s.Position)) { + var tokenizedState = _tokenizer.Replace(sortCriterion.State, tokens); var sortCriterionContext = new SortCriterionContext { Query = contentQuery, - State = FormParametersHelper.ToDynamic(sortCriterion.State) + State = FormParametersHelper.ToDynamic(tokenizedState), + QueryPartRecord = queryRecord, + Tokens = tokens }; string category = sortCriterion.Category; diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Services/PropertyShapes.cs b/src/Orchard.Web/Modules/Orchard.Projections/Services/PropertyShapes.cs index d2d11eae69d..d155f33f0ee 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Services/PropertyShapes.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Services/PropertyShapes.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Web.Mvc; +using Orchard.Conditions.Services; using Orchard.ContentManagement; using Orchard.DisplayManagement; using Orchard.Environment; @@ -13,9 +14,12 @@ namespace Orchard.Projections.Services { public class PropertyShapes : IDependency { private readonly Work _tokenizerWork; + private readonly Work _conditionManagerWork; + private readonly Dictionary _evaluations = new Dictionary(); - public PropertyShapes(Work tokenizerWork) { + public PropertyShapes(Work tokenizerWork, Work conditionManagerWork) { _tokenizerWork = tokenizerWork; + _conditionManagerWork = conditionManagerWork; T = NullLocalizer.Instance; } @@ -24,7 +28,7 @@ public PropertyShapes(Work tokenizerWork) { [Shape] public void Properties(dynamic Display, TextWriter Output, HtmlHelper Html, IEnumerable Items) { foreach (var item in Items) { - if((bool)item.Property.ExcludeFromDisplay) { + if ((bool)item.Property.ExcludeFromDisplay) { continue; } @@ -32,54 +36,55 @@ public void Properties(dynamic Display, TextWriter Output, HtmlHelper Html, IEnu } } - [Shape] + [Shape] public void LayoutGroup(dynamic Display, TextWriter Output, HtmlHelper Html, dynamic Key, dynamic List) { - Output.WriteLine(Display(Key)); + Output.WriteLine(Display(Key)); Output.WriteLine(Display(List)); } [Shape] public void PropertyWrapper( - dynamic Display, - TextWriter Output, + dynamic Display, + TextWriter Output, HtmlHelper Html, - UrlHelper Url, + UrlHelper Url, dynamic Item, ContentItem ContentItem, ContentItemMetadata ContentItemMetadata, - PropertyRecord Property - ) { - - // Display will encode any string which is not IHtmlString + PropertyRecord Property) { + // Display will encode any string which is not IHtmlString. string resultOutput = Convert.ToString(Display(Item)); - var resultIsEmpty = String.IsNullOrEmpty(resultOutput) || (resultOutput == "0" && Property.ZeroIsEmpty); - if(Property.HideEmpty && resultIsEmpty) { - return; - } + var tokenData = new Dictionary { { "Text", resultOutput }, { "Content", ContentItem } }; + + if (!string.IsNullOrWhiteSpace(Property.RewriteOutputCondition) && + _conditionManagerWork.Value.Matches(_tokenizerWork.Value.Replace(Property.RewriteOutputCondition, tokenData))) + resultOutput = string.IsNullOrWhiteSpace(Property.RewriteText) ? "" : _tokenizerWork.Value.Replace(Property.RewriteText, tokenData); - if(Property.RewriteOutput) { - resultOutput = _tokenizerWork.Value.Replace(Property.RewriteText, new Dictionary { { "Text", resultOutput }, { "Content", ContentItem } }); + var resultIsEmpty = string.IsNullOrEmpty(resultOutput) || (resultOutput == "0" && Property.ZeroIsEmpty); + + if (Property.HideEmpty && resultIsEmpty) { + return; } - if(Property.StripHtmlTags) { + if (Property.StripHtmlTags) { resultOutput = resultOutput.RemoveTags(); } - if(Property.TrimLength) { + if (Property.TrimLength) { var ellipsis = Property.AddEllipsis ? " …" : ""; resultOutput = resultOutput.Ellipsize(Property.MaxLength, ellipsis, Property.TrimOnWordBoundary); } - if(Property.TrimWhiteSpace) { + if (Property.TrimWhiteSpace) { resultOutput = resultOutput.Trim(); } - if(Property.PreserveLines) { - using(var sw = new StringWriter()) { - using(var sr = new StringReader(resultOutput)) { + if (Property.PreserveLines) { + using (var sw = new StringWriter()) { + using (var sr = new StringReader(resultOutput)) { string line; - while(null != (line = sr.ReadLine())) { + while (null != (line = sr.ReadLine())) { sw.WriteLine(line); sw.WriteLine("
        "); } @@ -89,7 +94,7 @@ PropertyRecord Property } var wrapperTag = new TagBuilder(Property.CustomizeWrapperHtml && !String.IsNullOrEmpty(Property.CustomWrapperTag) ? Property.CustomWrapperTag : "div"); - + if (Property.CustomizeWrapperHtml && !String.IsNullOrEmpty(Property.CustomWrapperCss)) { wrapperTag.AddCssClass(_tokenizerWork.Value.Replace(Property.CustomWrapperCss, new Dictionary())); } @@ -113,11 +118,11 @@ PropertyRecord Property if (!(Property.CustomizeLabelHtml && Property.CustomLabelTag == "-")) { Output.Write(labelTag.ToString(TagRenderMode.EndTag)); - } + } } var propertyTag = new TagBuilder(Property.CustomizePropertyHtml && !String.IsNullOrEmpty(Property.CustomPropertyTag) ? Property.CustomPropertyTag : "span"); - + if (Property.CustomizePropertyHtml && !String.IsNullOrEmpty(Property.CustomPropertyCss)) { propertyTag.AddCssClass(_tokenizerWork.Value.Replace(Property.CustomPropertyCss, new Dictionary())); } diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Settings/ProjectionPartEditorEvents.cs b/src/Orchard.Web/Modules/Orchard.Projections/Settings/ProjectionPartEditorEvents.cs new file mode 100644 index 00000000000..8460e2ad59a --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Projections/Settings/ProjectionPartEditorEvents.cs @@ -0,0 +1,270 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Orchard.ContentManagement; +using Orchard.ContentManagement.MetaData; +using Orchard.ContentManagement.MetaData.Builders; +using Orchard.ContentManagement.MetaData.Models; +using Orchard.ContentManagement.ViewModels; +using Orchard.ContentTypes.Events; +using Orchard.Core.Title.Models; +using Orchard.Data; +using Orchard.Forms.Services; +using Orchard.Localization; +using Orchard.Projections.Descriptors.Layout; +using Orchard.Projections.Models; +using Orchard.Projections.Services; +using Orchard.Projections.ViewModels; +using Orchard.UI.Notify; + +namespace Orchard.Projections.Settings { + public class ProjectionPartEditorEvents : ContentDefinitionEditorEventsBase, IContentDefinitionEventHandler { + private readonly IProjectionManager _projectionManager; + private readonly IContentManager _contentManager; + private readonly IRepository _layoutRepository; + private readonly IContentDefinitionManager _contentDefinitionManager; + + public ProjectionPartEditorEvents( + IOrchardServices services, + IProjectionManager projectionManager, + IContentManager contentManager, + IRepository layoutRepository, + IContentDefinitionManager contentDefinitionManager) { + + _projectionManager = projectionManager; + _contentManager = contentManager; + _layoutRepository = layoutRepository; + _contentDefinitionManager = contentDefinitionManager; + Services = services; + T = NullLocalizer.Instance; + } + public Localizer T { get; set; } + + public IOrchardServices Services { get; set; } + + public override IEnumerable TypePartEditor(ContentTypePartDefinition definition) { + if (definition.PartDefinition.Name == "ProjectionPart") { + var model = definition.Settings.GetModel(); + model.QueryRecordEntries = GetQueriesRecordEntry(); + if (!string.IsNullOrWhiteSpace(model.FilterQueryRecordId)) { + model.FilterQueryRecordsId = model.FilterQueryRecordId.Split('&'); + } + yield return DefinitionTemplate(model); + } + } + + public override IEnumerable TypePartEditorUpdate(ContentTypePartDefinitionBuilder builder, IUpdateModel updateModel) { + if (builder.Name != "ProjectionPart") { + yield break; + } + + var model = new ProjectionPartSettings(); + model.QueryRecordEntries = GetQueriesRecordEntry(); + + + if (updateModel.TryUpdateModel(model, "ProjectionPartSettings", null, null)) { + if (model.FilterQueryRecordsId != null && model.FilterQueryRecordsId.Count() > 0) { + // check if default query selected is in filter queries list + if (!model.FilterQueryRecordsId.Contains(model.QueryLayoutRecordId) && model.QueryLayoutRecordId != "-1") { + updateModel.AddModelError("ProjectionPart", T("The default query must be one of the selected queries")); + } + + // also save the identity part of the query and guid of the layout to be used in the import + model.IdentityQueryLayoutRecord = GetIdentityQueryLayout(model.QueryLayoutRecordId); + + model.FilterQueryRecordId = string.Join("&", model.FilterQueryRecordsId); + + List identityForFilterQuery = new List(); + foreach (var record in model.FilterQueryRecordsId) { + identityForFilterQuery.Add(GetIdentityQueryLayout(record)); + } + model.IdentityFilterQueryRecord = string.Join("&", identityForFilterQuery); + } + + builder + .WithSetting("ProjectionPartSettings.QueryLayoutRecordId", model.QueryLayoutRecordId) + .WithSetting("ProjectionPartSettings.IdentityQueryLayoutRecord", model.IdentityQueryLayoutRecord) + .WithSetting("ProjectionPartSettings.FilterQueryRecordId", model.FilterQueryRecordId) + .WithSetting("ProjectionPartSettings.IdentityFilterQueryRecord", model.IdentityFilterQueryRecord) + .WithSetting("ProjectionPartSettings.Items", model.Items.ToString()) + .WithSetting("ProjectionPartSettings.LockEditingItems", model.LockEditingItems.ToString()) + .WithSetting("ProjectionPartSettings.Skip", model.Skip.ToString()) + .WithSetting("ProjectionPartSettings.LockEditingSkip", model.LockEditingSkip.ToString()) + .WithSetting("ProjectionPartSettings.MaxItems", model.MaxItems.ToString()) + .WithSetting("ProjectionPartSettings.LockEditingMaxItems", model.LockEditingMaxItems.ToString()) + .WithSetting("ProjectionPartSettings.PagerSuffix", model.PagerSuffix) + .WithSetting("ProjectionPartSettings.LockEditingPagerSuffix", model.LockEditingPagerSuffix.ToString()) + .WithSetting("ProjectionPartSettings.DisplayPager", model.DisplayPager.ToString()) + .WithSetting("ProjectionPartSettings.LockEditingDisplayPager", model.LockEditingDisplayPager.ToString()); + } + yield return DefinitionTemplate(model); + } + + #region Implementation interface + public void ContentFieldAttached(ContentFieldAttachedContext context) { + } + + public void ContentFieldDetached(ContentFieldDetachedContext context) { + } + + public void ContentPartAttached(ContentPartAttachedContext context) { + } + + public void ContentPartCreated(ContentPartCreatedContext context) { + } + + public void ContentPartDetached(ContentPartDetachedContext context) { + } + + public void ContentPartImported(ContentPartImportedContext context) { + } + + public void ContentPartImporting(ContentPartImportingContext context) { + } + + public void ContentPartRemoved(ContentPartRemovedContext context) { + } + + public void ContentTypeCreated(ContentTypeCreatedContext context) { + } + + public void ContentTypeImported(ContentTypeImportedContext context) { + var part = context.ContentTypeDefinition.Parts + .ToList() + .Where(p => p.PartDefinition.Name == "ProjectionPart") + .FirstOrDefault(); + if (part != null) { + var settings = part.Settings.GetModel(); + + // from identity part of the query and guid of the layout find reference + settings.QueryLayoutRecordId = string.IsNullOrWhiteSpace(settings.IdentityQueryLayoutRecord) + ? "-1" : GetQueryLayoutRecord(settings.IdentityQueryLayoutRecord); + + if (!string.IsNullOrWhiteSpace(settings.IdentityFilterQueryRecord)) { + List identityForFilterQuery = new List(); + foreach (var record in settings.IdentityFilterQueryRecord.Split('&').ToList()) { + var correctId = GetQueryLayoutRecord(record); + if (!string.IsNullOrEmpty(correctId)) { + identityForFilterQuery.Add(correctId); + } + } + settings.FilterQueryRecordId = string.Join("&", identityForFilterQuery); + } + else { + settings.FilterQueryRecordId = string.Empty; + } + + _contentDefinitionManager.AlterTypeDefinition(context.ContentTypeDefinition.Name, cfg => cfg + .WithPart(part.PartDefinition.Name, + pb => pb + .WithSetting("ProjectionPartSettings.QueryLayoutRecordId", settings.QueryLayoutRecordId) + .WithSetting("ProjectionPartSettings.FilterQueryRecordId", settings.FilterQueryRecordId)) + ); + } + } + + public void ContentTypeImporting(ContentTypeImportingContext context) { + } + + public void ContentTypeRemoved(ContentTypeRemovedContext context) { + } + #endregion + + private string GetQueryLayoutRecord(string record) { + var ids = record.Split(';'); + if (ids.Count() == 1) { + // if is present only -1, the default query has not been selected + return ids[0]; + } + else { + string stringIds = string.Empty; + + var ciIdentity = _contentManager.ResolveIdentity(new ContentIdentity(ids[0])); + if (ciIdentity != null) { + stringIds = ciIdentity.Id.ToString() + ";"; + + if (ids[1] == "-1") { + // default layout + stringIds += "-1"; + } + else { + var recordLayout = _layoutRepository.Fetch(l => l.GUIdentifier == ids[1]).FirstOrDefault(); + if (recordLayout != null) { + stringIds += recordLayout.Id.ToString(); + } + } + } + return stringIds; + } + } + private string GetIdentityQueryLayout(string record) { + + var ids = record.Split(';'); + if (ids.Count() == 1) { + // if is present only -1, the default query has not been selected + return ids[0]; + } + else { + // ids[0] is id of query + // ids[1] is record id of layout + var identityQueryLayout = string.Empty; + // identity part to identify the query + var content = _contentManager.Get(int.Parse(ids[0])); + if (content != null) { + var identity = _contentManager.GetItemMetadata(content).Identity; + if (identity != null) { + identityQueryLayout = identity.ToString() + ";"; + } + else { + Services.Notifier.Error(T("ProjectionPart - Query - The loaded id {0} does not exist", ids[0])); + } + } + // guid id to identify the layout + if (ids[1] == "-1") { + // default layout + identityQueryLayout += ids[1]; + } + else { + var layoutRecord = _layoutRepository.Get(int.Parse(ids[1])); + if (layoutRecord != null) { + identityQueryLayout += layoutRecord.GUIdentifier; + } + else { + Services.Notifier.Error(T("ProjectionPart - Layout of query - The loaded id {0} does not exist", ids[1])); + } + } + return identityQueryLayout; + } + } + + private IEnumerable GetQueriesRecordEntry() { + // populating the list of queries and layouts + var layouts = _projectionManager.DescribeLayouts().SelectMany(x => x.Descriptors).ToList(); + + List records = new List(); + records.Add(new QueryRecordEntry { + Id = -1, + Name = T("No default").Text, + LayoutRecordEntries = new List() + }); + + records.AddRange(Services.ContentManager.Query().Join().OrderBy(x => x.Title).List() + .Select(x => new QueryRecordEntry { + Id = x.Id, + Name = x.Name, + LayoutRecordEntries = x.Layouts + .Select(l => new LayoutRecordEntry { + Id = l.Id, + Description = GetLayoutDescription(layouts, l) + }) + .ToList() + })); + return records; + } + + private string GetLayoutDescription(IEnumerable layouts, LayoutRecord l) { + var descriptor = layouts.FirstOrDefault(x => l.Category == x.Category && l.Type == x.Type); + return String.IsNullOrWhiteSpace(l.Description) ? descriptor.Display(new LayoutContext { State = FormParametersHelper.ToDynamic(l.State) }).Text : l.Description; + } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Settings/ProjectionPartSettings.cs b/src/Orchard.Web/Modules/Orchard.Projections/Settings/ProjectionPartSettings.cs new file mode 100644 index 00000000000..e86184a292d --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Projections/Settings/ProjectionPartSettings.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.ComponentModel; +using Orchard.Projections.ViewModels; + +namespace Orchard.Projections.Settings { + public class ProjectionPartSettings { + public ProjectionPartSettings() { + FilterQueryRecordsId = new List(); + } + + public string QueryLayoutRecordId { get; set; } + // saved identity part for import + public string IdentityQueryLayoutRecord { get; set; } + public IEnumerable QueryRecordEntries { get; set; } + public IEnumerable FilterQueryRecordsId { get; set; } + public string FilterQueryRecordId { get; set; } + // saved identity part for import + public string IdentityFilterQueryRecord { get; set; } + public int Items { get; set; } + public bool LockEditingItems { get; set; } + [DisplayName("Offset")] + public int Skip { get; set; } + public bool LockEditingSkip { get; set; } + public int MaxItems { get; set; } + public bool LockEditingMaxItems { get; set; } + public string PagerSuffix { get; set; } + public bool LockEditingPagerSuffix { get; set; } + public bool DisplayPager { get; set; } + public bool LockEditingDisplayPager { get; set; } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/StandardQueries/QueryFeedQuery.cs b/src/Orchard.Web/Modules/Orchard.Projections/StandardQueries/QueryFeedQuery.cs index d53d7228b5c..07b0d629ef7 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/StandardQueries/QueryFeedQuery.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/StandardQueries/QueryFeedQuery.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using System.Xml.Linq; @@ -11,22 +10,22 @@ using Orchard.Projections.Models; using Orchard.Projections.Services; using Orchard.Services; -using Orchard.Utility.Extensions; -namespace Orchard.Projections.StandardQueries { +namespace Orchard.Projections.StandardQueries +{ public class QueryFeedQuery : IFeedQueryProvider, IFeedQuery { private readonly IContentManager _contentManager; private readonly IProjectionManager _projectionManager; - private readonly IEnumerable _htmlFilters; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; public QueryFeedQuery( IContentManager contentManager, IProjectionManager projectionManager, - IEnumerable htmlFilters) + IHtmlFilterProcessor htmlFilterProcessor) { _contentManager = contentManager; _projectionManager = projectionManager; - _htmlFilters = htmlFilters; + _htmlFilterProcessor = htmlFilterProcessor; } public FeedQueryMatch Match(FeedContext context) { @@ -55,7 +54,7 @@ public void Execute(FeedContext context) { return; } - var inspector = new ItemInspector(container, _contentManager.GetItemMetadata(container), _htmlFilters); + var inspector = new ItemInspector(container, _contentManager.GetItemMetadata(container), _htmlFilterProcessor); if (context.Format == "rss") { var link = new XElement("link"); context.Response.Element.SetElementValue("title", inspector.Title); diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Tests/Orchard.Projections.Tests.csproj b/src/Orchard.Web/Modules/Orchard.Projections/Tests/Orchard.Projections.Tests.csproj index 248e0641bf9..2cbf78b35d8 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Tests/Orchard.Projections.Tests.csproj +++ b/src/Orchard.Web/Modules/Orchard.Projections/Tests/Orchard.Projections.Tests.csproj @@ -10,7 +10,8 @@ Properties Orchard.Projections.Tests Orchard.Projections.Tests - v4.5.2 + v4.8 + 7.3 512
        @@ -35,44 +36,48 @@ false + + ..\..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll + ..\..\..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll - True - - ..\..\..\..\packages\FluentNHibernate.2.0.3.0\lib\net40\FluentNHibernate.dll - True + + ..\..\..\..\packages\FluentNHibernate.3.1.0\lib\net461\FluentNHibernate.dll - - ..\..\..\..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll - True + + ..\..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll - ..\..\..\..\packages\Moq.4.2.1510.2205\lib\NET40\Moq.dll - True + ..\..\..\..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll - - ..\..\..\..\packages\NHibernate.4.0.1.4000\lib\net40\NHibernate.dll - True + + ..\..\..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll ..\..\..\..\packages\NUnit.2.5.10.11092\lib\nunit.framework.dll - True ..\..\..\..\packages\NUnit.2.5.10.11092\lib\nunit.mocks.dll - True ..\..\..\..\packages\NUnit.2.5.10.11092\lib\pnunit.framework.dll - True + + + ..\..\..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll + + + ..\..\..\..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll + ..\..\..\..\..\lib\sqlce\System.Data.SqlServerCe.dll True + + diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Tests/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Projections/Tests/Properties/AssemblyInfo.cs index 4a94052c79c..94ba8ee68ea 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Tests/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Tests/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Tests/Services/FieldIndexServiceTests.cs b/src/Orchard.Web/Modules/Orchard.Projections/Tests/Services/FieldIndexServiceTests.cs index 0d3e3d802b5..1107e7dcc6d 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Tests/Services/FieldIndexServiceTests.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Tests/Services/FieldIndexServiceTests.cs @@ -34,7 +34,6 @@ public override void Register(ContainerBuilder builder) { builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); - builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Tests/Services/FieldIndexStorageTests.cs b/src/Orchard.Web/Modules/Orchard.Projections/Tests/Services/FieldIndexStorageTests.cs index 6bdcc1b1742..6acbff08c6d 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Tests/Services/FieldIndexStorageTests.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Tests/Services/FieldIndexStorageTests.cs @@ -42,7 +42,6 @@ public override void Register(ContainerBuilder builder) { builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); - builder.RegisterType().As(); builder.RegisterType().As(); diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Tests/app.config b/src/Orchard.Web/Modules/Orchard.Projections/Tests/app.config index b04735a1b90..476eb41bdac 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Tests/app.config +++ b/src/Orchard.Web/Modules/Orchard.Projections/Tests/app.config @@ -4,11 +4,11 @@ - + - + @@ -16,8 +16,16 @@ - + + + + + + + + + - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Tests/packages.config b/src/Orchard.Web/Modules/Orchard.Projections/Tests/packages.config index 223030f6f06..d0e0056181b 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Tests/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Projections/Tests/packages.config @@ -1,9 +1,12 @@  - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/FilterEditViewModel.cs b/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/FilterEditViewModel.cs index 8a7f51ec0c4..47ec05e86fc 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/FilterEditViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/FilterEditViewModel.cs @@ -1,4 +1,5 @@ using Orchard.Projections.Descriptors.Filter; +using Orchard.Projections.Models; namespace Orchard.Projections.ViewModels { @@ -7,5 +8,6 @@ public class FilterEditViewModel { public string Description { get; set; } public FilterDescriptor Filter { get; set; } public dynamic Form { get; set; } + public QueryVersionScopeOptions VersionScope { get; set; } } } diff --git a/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/ProjectionPartEditViewModel.cs b/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/ProjectionPartEditViewModel.cs index 8a707e1e0be..8ae4fbad8f6 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/ProjectionPartEditViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/ProjectionPartEditViewModel.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.ComponentModel; using System.ComponentModel.DataAnnotations; namespace Orchard.Projections.ViewModels { @@ -10,7 +11,7 @@ public class ProjectionPartEditViewModel { [Required, Range(0, int.MaxValue)] public int ItemsPerPage { get; set; } - [Required, Range(0, int.MaxValue)] + [Required, Range(0, int.MaxValue),DisplayName("Offset")] public int Skip { get; set; } public string PagerSuffix { get; set; } @@ -24,6 +25,17 @@ public class ProjectionPartEditViewModel { public string QueryLayoutRecordId { get; set; } public IEnumerable QueryRecordEntries { get; set; } + public IEnumerable QueryRecordIdFilterEntries { get; set; } + + public int PartId { get; set; } + + // manage Lock items + public bool LockEditingItems { get; set; } + public bool LockEditingSkip { get; set; } + public bool LockEditingMaxItems { get; set; } + public bool LockEditingPagerSuffix { get; set; } + public bool LockEditingDisplayPager { get; set; } + } public class QueryRecordEntry { @@ -36,4 +48,8 @@ public class LayoutRecordEntry { public int Id { get; set; } public string Description { get; set; } } + public class QueryRecordFilterEntry { + public string Id { get; set; } + public string LayoutId { get; set; } + } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/PropertyEditViewModel.cs b/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/PropertyEditViewModel.cs index e529dc46056..fa6711ce6bb 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/PropertyEditViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/PropertyEditViewModel.cs @@ -42,8 +42,7 @@ public class PropertyEditViewModel { public bool ZeroIsEmpty { get; set; } public bool HideEmpty { get; set; } - public bool RewriteOutput { get; set; } - [StringLength(255)] + public string RewriteOutputCondition { get; set; } public string RewriteText { get; set; } public bool StripHtmlTags { get; set; } public bool TrimLength { get; set; } diff --git a/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/QueryViewModel.cs b/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/QueryViewModel.cs new file mode 100644 index 00000000000..4acb990304f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Projections/ViewModels/QueryViewModel.cs @@ -0,0 +1,7 @@ +using Orchard.Projections.Models; + +namespace Orchard.Projections.ViewModels { + public class QueryViewModel { + public QueryVersionScopeOptions VersionScope { get; set; } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Views/Admin/Edit.cshtml b/src/Orchard.Web/Modules/Orchard.Projections/Views/Admin/Edit.cshtml index bd8424da9fe..4c432900ca6 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Views/Admin/Edit.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Projections/Views/Admin/Edit.cshtml @@ -12,7 +12,7 @@

        @T("Filters")

        - +
        @Html.ActionLink(T("Add a new Group").Text, "AddGroup", new { controller = "Filter", id = Model.Id }, new { @class = "button primaryAction" })
        @@ -20,32 +20,43 @@ foreach (var group in Model.FilterGroups) { bool isFirstGroup = group == Model.FilterGroups.First(); if (!isFirstGroup) { -

        @T("Or")

        +

        @T("Or")

        } - - - - - - - - - @foreach (var filter in group.Filters) { - - - - - } -
        @T("Description") - @Html.ActionLink(T("+ Add a new Filter").Text, "Add", new { controller = "Filter", id = group.Id }) - @if (Model.FilterGroups.Count() > 1) { - | @Html.ActionLink(T("Delete group").Text, "DeleteGroup", new { controller = "Filter", id = group.Id }, new { itemprop = "RemoveUrl UnsafeUrl" }) - } -
        @filter.DisplayText - @Html.ActionLink(T("Edit").Text, "Edit", new { controller = "Filter", id = group.Id, category = filter.Category, type = filter.Type, filterId = filter.FilterRecordId }) | - @Html.ActionLink(T("Delete").Text, "Delete", new { controller = "Filter", id = Model.Id, filterId = filter.FilterRecordId }, new { itemprop = "RemoveUrl UnsafeUrl" }) -
        + + + + + + + + @foreach (var filter in group.Filters) { + + + + + } +
        @T("Description") + +
        @filter.DisplayText + +
        }
        @@ -55,25 +66,33 @@ - + - @foreach (var sortCriterion in Model.SortCriteria) { - - - - - } + @foreach (var sortCriterion in Model.SortCriteria) { + + + + + }
        @T("Description")@T("Description") @Html.ActionLink(T("+ Add a new Sort Criteria").Text, "Add", new { controller = "SortCriterion", id = Model.Id })
        @sortCriterion.DisplayText - @Html.ActionLink(T("Edit").Text, "Edit", new { controller = "SortCriterion", id = Model.Id, category = sortCriterion.Category, type = sortCriterion.Type, sortCriterionId = sortCriterion.SortCriterionRecordId }) | - @Html.ActionLink(T("Delete").Text, "Delete", new { controller = "SortCriterion", id = Model.Id, sortCriterionId = sortCriterion.SortCriterionRecordId }, new { itemprop = "RemoveUrl UnsafeUrl" }) - @if (sortCriterion != Model.SortCriteria.First()) { - | @Html.ActionLink(T("Up").Text, "Move", new { controller = "SortCriterion", id = sortCriterion.SortCriterionRecordId, direction = "up", queryId = Model.Id }) - } - @if (sortCriterion != Model.SortCriteria.Last()) { - | @Html.ActionLink(T("Down").Text, "Move", new { controller = "SortCriterion", id = sortCriterion.SortCriterionRecordId, direction = "down", queryId = Model.Id }) - } -
        @sortCriterion.DisplayText + +
        @@ -83,35 +102,38 @@ - + - @foreach (var layout in Model.Layouts) { - - - - - } + @foreach (var layout in Model.Layouts) { + + + + + }
        @T("Description")@T("Description") @Html.ActionLink(T("+ Add a new Layout").Text, "Add", new { controller = "Layout", id = Model.Id })
        @(layout.DisplayText) - @Html.ActionLink(T("Edit").Text, "Edit", new { controller = "Layout", id = layout.LayoutRecordId }) | - @Html.ActionLink(T("Delete").Text, "Delete", new { controller = "Layout", id = layout.LayoutRecordId }, new { itemprop = "RemoveUrl UnsafeUrl" }) -
        @(layout.DisplayText) + +
        @* Render a button at the bottom only if there are several layouts in the table *@ if (Model.Layouts.Count() > 5) {
        - @Html.ActionLink(T("Add a new Layout").Text, "Add", new { controller = "Layout", id = Model.Id }, new { @class = "button primaryAction" }) + @Html.ActionLink(T("Add a new Layout").Text, "Add", new { controller = "Layout", id = Model.Id }, new { @class = "button primaryAction" })
        } - -
        - @if(Model.FilterGroups.SelectMany(x => x.Filters).Any()) { + @if (Model.FilterGroups.SelectMany(x => x.Filters).Any()) { @Html.ActionLink(T("Preview").ToString(), "Preview", new { Model.Id }, new { @class = "button" }); } @Html.ActionLink(T("Close").ToString(), "Index", new { }, new { @class = "button" })
        - } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Projections/Views/Admin/Index.cshtml index da01e727089..d4fc5a43b03 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Projections/Views/Admin/Index.cshtml @@ -4,14 +4,14 @@ @{ Style.Include("admin-projections.css"); - Layout.Title = T("Manage Queries").ToString(); + Layout.Title = T("Manage Queries").ToString(); var index = 0; - var pageSizes = new List() { 10, 50, 100 }; - var defaultPageSize = WorkContext.CurrentSite.PageSize; - if(!pageSizes.Contains(defaultPageSize)) { - pageSizes.Add(defaultPageSize); - } + var pageSizes = new List() { 10, 50, 100 }; + var defaultPageSize = WorkContext.CurrentSite.PageSize; + if(!pageSizes.Contains(defaultPageSize)) { + pageSizes.Add(defaultPageSize); + } }

        @Html.TitleForPage(T("Manage Queries").ToString())

        @@ -19,7 +19,7 @@ @Html.ValidationSummary()
        @Html.ActionLink(T("Add a new Query").ToString(), "Create", new { Area = "Contents", id = "Query", returnurl = HttpContext.Current.Request.RawUrl }, new { @class = "button primaryAction" })
        - @T(" | ") + @Html.SelectOption(Model.Options.Order, QueriesOrder.Name, T("Name").ToString()) - - - + + +
        @@ -61,17 +61,27 @@ @Html.ActionLink(entry.Name, "Edit", new { id = entry.QueryId }) - @Html.ActionLink(T("Properties").ToString(), "Edit", new { Area = "Contents", id = entry.QueryId, returnurl = HttpContext.Current.Request.RawUrl }) | - @Html.ActionLink(T("Edit").ToString(), "Edit", new { id = entry.QueryId }) | - @Html.ActionLink(T("Delete").ToString(), "Delete", new { id = entry.QueryId }, new { itemprop = "RemoveUrl UnsafeUrl" }) - @if (entry.Query.FilterGroups.SelectMany(x => x.Filters).Any()) { - | @Html.ActionLink(T("Preview").ToString(), "Preview", new { id = entry.QueryId }) - } + index++; } - @Display(Model.Pager) + @Display(Model.Pager)
        } diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Views/Binding/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Projections/Views/Binding/Index.cshtml index 8bc4a74723e..e9d88d29e59 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Views/Binding/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Projections/Views/Binding/Index.cshtml @@ -15,7 +15,7 @@ }

        @Html.TitleForPage(T("Manage Bindings").ToString())

        -@using (Html.BeginFormAntiForgeryPost()) { +@using (Html.BeginFormAntiForgeryPost()) { @Html.ValidationSummary()
        @Html.ActionLink(T("Add a new Binding").ToString(), "Select", new { }, new { @class = "button primaryAction" })
        @@ -28,38 +28,38 @@
        - + - - - + + +
        } -
        - - - - - - - - - - - - @foreach (var entry in Model.Bindings) { - +
        +
         ↓@T("Type")@T("Member")@T("Display")@T("Description") 
        + + + + + + + + + + + @foreach (var entry in Model.Bindings) { + - index++; - } -
         ↓@T("Type")@T("Member")@T("Display")@T("Description") 
        - - + + @entry.Binding.Type @@ -74,18 +74,24 @@ @entry.Binding.Description - @Html.ActionLink(T("Edit").ToString(), "Edit", new { entry.Binding.Id }) | - @using (Html.BeginFormAntiForgeryPost(Url.Action("Delete"), FormMethod.Post, new { @class = "inline link" })) { - @Html.Hidden("id", entry.Binding.Id) - - } +
        -
        + index++; + } + +
        -@using (Html.BeginFormAntiForgeryPost()) { - @Display(Model.Pager) +@using (Html.BeginFormAntiForgeryPost()) { + @Display(Model.Pager) } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Views/DefinitionTemplates/ProjectionPartSettings.cshtml b/src/Orchard.Web/Modules/Orchard.Projections/Views/DefinitionTemplates/ProjectionPartSettings.cshtml new file mode 100644 index 00000000000..c1d210a6ee1 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Projections/Views/DefinitionTemplates/ProjectionPartSettings.cshtml @@ -0,0 +1,112 @@ +@model Orchard.Projections.Settings.ProjectionPartSettings +@using Orchard.Projections.Models; +@using Orchard.Projections.ViewModels; + +
        + @Html.LabelFor(m => m.QueryLayoutRecordId, T("Default Query")) + + @T("The query to display.") +
        +
        + @T("Select lock editing to prevent the user from editing the default choice") + +
        +
        +
        + @Html.LabelFor(m => m.Items, T("Items to display")) + @Html.TextBoxFor(m => m.Items, new { @class = "text small" }) +
        +
        + @Html.CheckBoxFor(m => m.LockEditingItems) + +
        +
        + @T("The number of items to display. Enter 0 for no limit. When using pagination, this is the number of items per page.") +
        + +
        +
        +
        + @Html.LabelFor(m => m.Skip, T("Offset")) + @Html.TextBoxFor(m => m.Skip, new { @class = "text small" }) +
        +
        + @Html.CheckBoxFor(m => m.LockEditingSkip) + +
        +
        + @T("The number of items to skip (e.g., if 2 is entered, the first 2 items won't be diplayed).") +
        + +
        +
        +
        + @Html.LabelFor(m => m.MaxItems, T("Maximum items")) + @Html.TextBoxFor(m => m.MaxItems, new { @class = "text small" }) +
        +
        + @Html.CheckBoxFor(m => m.LockEditingMaxItems) + +
        +
        + @T("Maximum number of items which can be queried at once. Use 0 for unlimited. This is only used as a failsafe when the number of items comes from a user-provided source such as the query string.") +
        + +
        +
        +
        + @Html.LabelFor(m => m.PagerSuffix, T("Suffix")) + @Html.TextBoxFor(m => m.PagerSuffix, new { @class = "text" }) +
        +
        + @Html.CheckBoxFor(m => m.LockEditingPagerSuffix) + +
        +
        + @T("Optional. Provide a suffix to use when multiple pagers are displayed on the same page, e.g., when using multiple Projection Widgets, or to define alternates.") +
        + +
        +
        +
        + @Html.CheckBoxFor(m => m.DisplayPager) + +
        +
        + @Html.CheckBoxFor(m => m.LockEditingDisplayPager) + +
        +
        + @T("Check to add a pager to the list.") +
        +
        +
        + @Html.LabelFor(m => m.FilterQueryRecordId, T("Filter Queries")) + + @T("Select which queries to display to the user. If there are no selections, all queries will be used.") +
        \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Views/EditorTemplates/Parts/ProjectionPart.cshtml b/src/Orchard.Web/Modules/Orchard.Projections/Views/EditorTemplates/Parts/ProjectionPart.cshtml index 78610823b1a..de113fabaf3 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Views/EditorTemplates/Parts/ProjectionPart.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Projections/Views/EditorTemplates/Parts/ProjectionPart.cshtml @@ -4,71 +4,154 @@ @{ var selectedQueryRecordId = -1; + + var filterQuery = Model.QueryRecordIdFilterEntries.Any(); + var checkQuery = false; } -
        - @Html.LabelFor(m => m.QueryLayoutRecordId, T("For Query")) - + @foreach (QueryRecordEntry queryRecord in Model.QueryRecordEntries.OrderBy(x => x.Name)) { + // check condition for design option group + bool designDefaultQuery = Model.QueryRecordIdFilterEntries.Any(x => x.Id == queryRecord.Id.ToString() && x.LayoutId == "-1"); + bool designAnotherLayout = Model.QueryRecordIdFilterEntries.Any(x => queryRecord.LayoutRecordEntries.Select(q => q.Id.ToString()).Contains(x.LayoutId)); + - @foreach (LayoutRecordEntry layoutRecord in queryRecord.LayoutRecordEntries.OrderBy(x => x.Description)) { - @Html.SelectOption(Model.QueryLayoutRecordId, queryRecord.Id + ";" + layoutRecord.Id, queryRecord.Name + " " + T("({0})", layoutRecord.Description).Text) - if (Model.QueryLayoutRecordId == queryRecord.Id + ";" + layoutRecord.Id) { - selectedQueryRecordId = queryRecord.Id; + if (!filterQuery || designDefaultQuery || designAnotherLayout) { + + @if (!filterQuery || designDefaultQuery) { + @Html.SelectOption(Model.QueryLayoutRecordId, queryRecord.Id + ";-1", queryRecord.Name + " " + T("(Default Layout)").Text) + if (Model.QueryLayoutRecordId == queryRecord.Id + ";-1") { + selectedQueryRecordId = queryRecord.Id; + checkQuery = true; + } + } + @foreach (LayoutRecordEntry layoutRecord in queryRecord.LayoutRecordEntries.OrderBy(x => x.Description)) { + if (!filterQuery || Model.QueryRecordIdFilterEntries.Any(x => x.Id == queryRecord.Id.ToString() && x.LayoutId == layoutRecord.Id.ToString())) { + @Html.SelectOption(Model.QueryLayoutRecordId, queryRecord.Id + ";" + layoutRecord.Id, queryRecord.Name + " " + T("({0})", layoutRecord.Description).Text) + if (Model.QueryLayoutRecordId == queryRecord.Id + ";" + layoutRecord.Id) { + selectedQueryRecordId = queryRecord.Id; + checkQuery = true; + } + } + } + } } - + + if (!checkQuery && Model.PartId != 0) { + + } } - - @if (selectedQueryRecordId != -1) { - @Html.ActionLink(T("Edit Query").Text, "Edit", new { area = "Orchard.Projections", id = selectedQueryRecordId }, new { }) - } - @T("The query to display.") -
        + @if (selectedQueryRecordId != -1) { + @Html.ActionLink(T("Edit Query").Text, "Edit", new { area = "Orchard.Projections", id = selectedQueryRecordId }, new { id = "editQueryLink-" + Model.PartId.ToString() }) + } + @T("The query to display.") +
        - @Html.LabelFor(m => m.Items, T("Items to display")) - @Html.TextBoxFor(m => m.Items, new { @class = "text small" }) - @T("The number of items to display. Enter 0 for no limit. When using pagination, this is the number of items per page.") + @if (Model.LockEditingItems) { + @Model.Items + @Html.HiddenFor(m => m.Items) + @HintFromLockedField(T("The number of items to display. If equals 0 no limit. When using pagination, this is the number of items per page.").Text) + } + else { + @Html.LabelFor(m => m.Items, T("Items to display")) + @Html.TextBoxFor(m => m.Items, new { @class = "text small" }) + @T("The number of items to display. Enter 0 for no limit. When using pagination, this is the number of items per page.") + }
        - @Html.LabelFor(m => m.Skip, T("Offset")) - @Html.TextBoxFor(m => m.Skip, new { @class = "text small" }) - @T("The number of items to skip (e.g., if 2 is entered, the first 2 items won't be diplayed).") + @if (Model.LockEditingSkip) { + @Model.Skip + @Html.HiddenFor(m => m.Skip) + @HintFromLockedField(T("The number of items to skip (e.g., if 2 is entered, the first 2 items won't be diplayed).").Text) + } + else { + @Html.LabelFor(m => m.Skip, T("Offset")) + @Html.TextBoxFor(m => m.Skip, new { @class = "text small" }) + @T("The number of items to skip (e.g., if 2 is entered, the first 2 items won't be diplayed).") + }
        - @Html.LabelFor(m => m.MaxItems, T("Maximum items")) - @Html.TextBoxFor(m => m.MaxItems, new { @class = "text small" }) - @T("Maximum number of items which can be queried at once. Use 0 for unlimited. This is only used as a failsafe when the number of items comes from a user-provided source such as the query string.") + @if (Model.LockEditingMaxItems) { + @Model.MaxItems + @Html.HiddenFor(m => m.MaxItems) + @HintFromLockedField(T("Maximum number of items which can be queried at once. Use 0 for unlimited. This is only used as a failsafe when the number of items comes from a user-provided source such as the query string.").Text) + } + else { + @Html.LabelFor(m => m.MaxItems, T("Maximum items")) + @Html.TextBoxFor(m => m.MaxItems, new { @class = "text small" }) + @T("Maximum number of items which can be queried at once. Use 0 for unlimited. This is only used as a failsafe when the number of items comes from a user-provided source such as the query string.") + }
        - @Html.LabelFor(m => m.PagerSuffix, T("Suffix")) - @Html.TextBoxFor(m => m.PagerSuffix, new { @class = "text" }) - @T("Optional. Provide a suffix to use when multiple pagers are displayed on the same page, e.g., when using multiple Projection Widgets, or to define alternates.") + @if (Model.LockEditingPagerSuffix) { + if (!string.IsNullOrEmpty(Model.PagerSuffix)) { + @Model.PagerSuffix + @HintFromLockedField(T("Optional. Provide a suffix to use when multiple pagers are displayed on the same page, e.g., when using multiple Projection Widgets, or to define alternates.").Text) + } + @Html.HiddenFor(m => m.PagerSuffix) + } + else { + @Html.LabelFor(m => m.PagerSuffix, T("Suffix")) + @Html.TextBoxFor(m => m.PagerSuffix, new { @class = "text small" }) + @T("Optional. Provide a suffix to use when multiple pagers are displayed on the same page, e.g., when using multiple Projection Widgets, or to define alternates.") + }
        - @Html.CheckBoxFor(m => m.DisplayPager) - - @T("Check to add a pager to the list.") + @if (Model.LockEditingDisplayPager) { + + if (Model.DisplayPager) { + @T("True") + } + else { + @T("False") + } + @Html.HiddenFor(m => m.DisplayPager) + @HintFromLockedField(T("Flag used to add a pager to the list.").Text) + } + else { + @Html.CheckBoxFor(m => m.DisplayPager) + + @T("Check to add a pager to the list.") + }
        @using (Script.Foot()) { - + } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Views/EditorTemplates/Parts/QueryPart_Edit.cshtml b/src/Orchard.Web/Modules/Orchard.Projections/Views/EditorTemplates/Parts/QueryPart_Edit.cshtml new file mode 100644 index 00000000000..74ca7b49fd5 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Projections/Views/EditorTemplates/Parts/QueryPart_Edit.cshtml @@ -0,0 +1,10 @@ +@using Orchard.Projections.Models; +@using Orchard.Projections.ViewModels; + +@model QueryViewModel + +
        + @Html.LabelFor(m => m.VersionScope, T("Content's version")) + @Html.DropDownListFor(m => m.VersionScope, new SelectList(Enum.GetValues(typeof(QueryVersionScopeOptions)), Model.VersionScope)) + @T("The content's version to query.") +
        diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Views/Property/Edit.cshtml b/src/Orchard.Web/Modules/Orchard.Projections/Views/Property/Edit.cshtml index 8496db38240..68e5e2ca439 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Views/Property/Edit.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Projections/Views/Property/Edit.cshtml @@ -49,8 +49,8 @@
        - @Html.TextBoxFor(m => m.Label, new { @class = "text medium tokenized" }) - @T("The text to display as a label for this property.") + @Html.TextBoxFor(m => m.Label, new { @class = "text large tokenized" }) + @T("The text to display as a label for this property. It may include HTML.")
        @@ -117,7 +117,7 @@
        - @Html.TextBoxFor(m => m.NoResultText, new { @class = "text medium tokenized" }) + @Html.TextBoxFor(m => m.NoResultText, new { @class = "text large tokenized" }) @T("Text to display when the property is empty.")
        @@ -141,16 +141,18 @@
        - @Html.CheckBoxFor(m => m.RewriteOutput) - - @T("Check to override the output of this property.") +
        + + @Html.TextBoxFor(m => m.RewriteOutputCondition, new { @class = "text large tokenized" }) + @T("A condition that will be evaluated to decide whether to rewrite the output or not.") +
        -
        +
        - @Html.TextBoxFor(m => m.RewriteText, new { @class = "text large tokenized" }) - @T("The text to write for this field. It may include HTML. {Text} can be used to inject the current property text.") + @Html.TextAreaFor(m => m.RewriteText, new { @class = "text large tokenized" }) + @T("The tokenized text that will be evaluated and applied if \"Rewrite output condition\" evaluates to true. It may include HTML and {Text} can be used to inject the current property text.")
        diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Web.config b/src/Orchard.Web/Modules/Orchard.Projections/Web.config index a3cb5df907e..baf3b31252b 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Projections/Web.config @@ -7,7 +7,7 @@ - + @@ -21,39 +21,58 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Projections/packages.config b/src/Orchard.Web/Modules/Orchard.Projections/packages.config index 96e09a98934..66dabff1308 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Projections/packages.config @@ -1,9 +1,13 @@  - - - - - - - \ No newline at end of file + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Drivers/PublishLaterPartDriver.cs b/src/Orchard.Web/Modules/Orchard.PublishLater/Drivers/PublishLaterPartDriver.cs index 8edefd9d51e..9efc3e4d9c0 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/Drivers/PublishLaterPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Drivers/PublishLaterPartDriver.cs @@ -11,6 +11,7 @@ using Orchard.PublishLater.Services; using Orchard.PublishLater.ViewModels; using Orchard.Services; +using Orchard.Tasks.Scheduling; namespace Orchard.PublishLater.Drivers { public class PublishLaterPartDriver : ContentPartDriver { @@ -19,19 +20,22 @@ public class PublishLaterPartDriver : ContentPartDriver { private readonly IPublishLaterService _publishLaterService; private readonly IClock _clock; private readonly IDateLocalizationServices _dateLocalizationServices; + private readonly IPublishingTaskManager _publishingTaskManager; public PublishLaterPartDriver( IOrchardServices services, IHttpContextAccessor httpContextAccessor, IPublishLaterService publishLaterService, IClock clock, - IDateLocalizationServices dateLocalizationServices) { + IDateLocalizationServices dateLocalizationServices, + IPublishingTaskManager publishingTaskManager) { _httpContextAccessor = httpContextAccessor; _publishLaterService = publishLaterService; _clock = clock; _dateLocalizationServices = dateLocalizationServices; T = NullLocalizer.Instance; Services = services; + _publishingTaskManager = publishingTaskManager; } public Localizer T { @@ -101,10 +105,13 @@ protected override DriverResult Editor(PublishLaterPart part, IUpdateModel updat } } else { - updater.AddModelError(Prefix, T("Both the date and time need to be specified for when this is to be published. If you don't want to schedule publishing then click Save or Publish Now.")); + updater.AddModelError(Prefix, T("Both the date and time need to be specified for when this is to be published. If you don't want to schedule publishing then click Save Draft or Publish.")); } } + if (httpContext.Request.Form["submit.Save"] == "submit.CancelPublishLaterTasks") { + _publishingTaskManager.DeleteTasks(model.ContentItem); + } return ContentShape("Parts_PublishLater_Edit", () => shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix)); } diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Module.txt b/src/Orchard.Web/Modules/Orchard.PublishLater/Module.txt index 0395daac61b..835e8872566 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Module.txt @@ -3,8 +3,8 @@ Path: PublishLater AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: The PublishLater module introduces draft creation and scheduled publishing functionality. FeatureDescription: Draft creation and scheduled publishing. Category: Content diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Orchard.PublishLater.csproj b/src/Orchard.Web/Modules/Orchard.PublishLater/Orchard.PublishLater.csproj index 32da044daca..3c58eeb1208 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/Orchard.PublishLater.csproj +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Orchard.PublishLater.csproj @@ -13,8 +13,8 @@ Properties Orchard.PublishLater Orchard.PublishLater - v4.5.2 - false + v4.8 + 7.3 @@ -27,6 +27,9 @@ + + + true @@ -49,10 +52,12 @@ false + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -62,28 +67,22 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -113,12 +112,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) @@ -150,7 +149,7 @@ - + 10.0 @@ -184,4 +183,4 @@ - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Placement.info b/src/Orchard.Web/Modules/Orchard.PublishLater/Placement.info index eec14fcbbf9..957ea658705 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/Placement.info +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Placement.info @@ -7,7 +7,7 @@ --> - + diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.PublishLater/Properties/AssemblyInfo.cs index 31c1654e8bd..8a5fa7bba5f 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Services/XmlRpcHandler.cs b/src/Orchard.Web/Modules/Orchard.PublishLater/Services/XmlRpcHandler.cs index dfc15774a80..2108793648e 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/Services/XmlRpcHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Services/XmlRpcHandler.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Xml.Linq; using Orchard.ContentManagement; using Orchard.Core.Contents; @@ -147,9 +148,10 @@ private static int GetId(XRpcMethodResponse response) { } private IUser ValidateUser(string userName, string password) { - IUser user = _membershipService.ValidateUser(userName, password); - if (user == null) { - throw new OrchardCoreException(T("The username or e-mail or password provided is incorrect.")); + List validationErrors; + IUser user = _membershipService.ValidateUser(userName, password, out validationErrors); + if (validationErrors.Any()) { + throw new OrchardCoreException(validationErrors.FirstOrDefault()); } return user; diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Views/EditorTemplates/Parts/PublishLater.cshtml b/src/Orchard.Web/Modules/Orchard.PublishLater/Views/EditorTemplates/Parts/PublishLater.cshtml index 8f0aa281cd4..f879e6eadbc 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/Views/EditorTemplates/Parts/PublishLater.cshtml +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Views/EditorTemplates/Parts/PublishLater.cshtml @@ -1,46 +1,47 @@ @model Orchard.PublishLater.ViewModels.PublishLaterViewModel -@using Orchard.ContentManagement; @using Orchard.Core.Contents; -@using Orchard.Utility.Extensions; @if (Authorizer.Authorize(Permissions.PublishContent, Model.ContentItem)) { - + } - .dir-rtl .publish-later-datetime button { - margin-left: inherit; - margin-right: 4px; - } - -
        @T("Publish") @Html.HiddenFor(m => m.Editor.ShowDate) @Html.HiddenFor(m => m.Editor.ShowTime) @Html.EditorFor(m => m.Editor) + @if (!string.IsNullOrEmpty(Model.Editor.Date)) { + + }
        using (Script.Foot()) { diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Views/Parts/PublishLater.Metadata.Summary.cshtml b/src/Orchard.Web/Modules/Orchard.PublishLater/Views/Parts/PublishLater.Metadata.Summary.cshtml index 74cb9df8310..ffaf5c98511 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/Views/Parts/PublishLater.Metadata.Summary.cshtml +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Views/Parts/PublishLater.Metadata.Summary.cshtml @@ -6,5 +6,5 @@ DateTime? publishedUtc = publishLaterPart.As() == null ? null : publishLaterPart.As().PublishedUtc; } @if (publishLaterPart.IsPublished() && publishedUtc.HasValue) { - @T("Published: {0}", Display.DateTimeRelative(DateTimeUtc: publishedUtc.Value)) @T(" | ") + @T("Published: {0}", Display.DateTimeRelative(DateTimeUtc: publishedUtc.Value)) } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Web.config b/src/Orchard.Web/Modules/Orchard.PublishLater/Web.config index 04411447dea..baf3b31252b 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/Web.config +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Web.config @@ -7,7 +7,7 @@ - + @@ -21,51 +21,58 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/packages.config b/src/Orchard.Web/Modules/Orchard.PublishLater/packages.config index 6729ced4977..1c55d6960bb 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/packages.config +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/packages.config @@ -1,7 +1,8 @@  - - - - - \ No newline at end of file + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/AdminMenu.cs b/src/Orchard.Web/Modules/Orchard.Recipes/AdminMenu.cs new file mode 100644 index 00000000000..c419ed197b0 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Recipes/AdminMenu.cs @@ -0,0 +1,23 @@ +using Orchard.Localization; +using Orchard.Security; +using Orchard.UI.Navigation; + +namespace Orchard.Recipes { + public class AdminMenu : INavigationProvider { + public Localizer T { get; set; } + + public string MenuName { + get { return "admin"; } + } + + public void GetNavigation(NavigationBuilder builder) { + builder.AddImageSet("modules").Add(T("Modules"), "9", BuildMenu); + } + + private void BuildMenu(NavigationItemBuilder menu) { + menu.Add(T("Recipes"), "2", item => item + .Action("Index", "Admin", new { area = "Orchard.Recipes" }) + .Permission(StandardPermissions.SiteOwner).LocalNav()); + } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Recipes/Controllers/AdminController.cs new file mode 100644 index 00000000000..632e501b021 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Controllers/AdminController.cs @@ -0,0 +1,124 @@ +using System.Linq; +using System.Web.Mvc; +using Orchard.DisplayManagement; +using Orchard.Environment.Configuration; +using Orchard.Environment.Extensions; +using Orchard.Environment.Extensions.Models; +using Orchard.Localization; +using Orchard.Logging; +using Orchard.Recipes.Services; +using Orchard.Recipes.ViewModels; +using Orchard.Security; +using Orchard.UI.Admin; +using Orchard.UI.Notify; + +namespace Orchard.Recipes.Controllers { + [Admin] + public class AdminController : Controller { + private readonly IExtensionManager _extensionManager; + private readonly IRecipeHarvester _recipeHarvester; + private readonly IRecipeManager _recipeManager; + private readonly IRecipeResultAccessor _recipeResultAccessor; + private readonly ShellSettings _shellSettings; + + public AdminController( + IOrchardServices services, + IExtensionManager extensionManager, + IRecipeHarvester recipeHarvester, + IRecipeManager recipeManager, + IRecipeResultAccessor recipeResultAccessor, + ShellSettings shellSettings, + IShapeFactory shapeFactory) { + Services = services; + _extensionManager = extensionManager; + _recipeHarvester = recipeHarvester; + _recipeManager = recipeManager; + _recipeResultAccessor = recipeResultAccessor; + _shellSettings = shellSettings; + + T = NullLocalizer.Instance; + Logger = NullLogger.Instance; + } + + public Localizer T { get; set; } + public IOrchardServices Services { get; set; } + public ILogger Logger { get; set; } + + public ActionResult Index() { + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not allowed to execute recipe files."))) + return new HttpUnauthorizedResult(); + + var modules = _extensionManager.AvailableExtensions() + .Where(extensionDescriptor => ExtensionIsAllowed(extensionDescriptor)) + .OrderBy(extensionDescriptor => extensionDescriptor.Name); + + var viewModel = new RecipesViewModel { + Modules = modules + .Select(x => new ModuleRecipesViewModel { + Descriptor = x, + Recipes = _recipeHarvester.HarvestRecipes(x.Id).Where(recipe => !recipe.IsSetupRecipe).ToList() + }) + .Where(x => x.Recipes.Any()) + .ToList() + }; + + return View(viewModel); + + } + + [HttpPost, ActionName("Recipes")] + public ActionResult RecipesPOST(string moduleId, string name) { + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not allowed to execute recipe files."))) + return new HttpUnauthorizedResult(); + + var module = _extensionManager.AvailableExtensions() + .Where(extensionDescriptor => extensionDescriptor.Id == moduleId && ExtensionIsAllowed(extensionDescriptor)) + .FirstOrDefault(); + + if (module == null) { + return HttpNotFound(); + } + + var recipe = _recipeHarvester.HarvestRecipes(module.Id).FirstOrDefault(x => !x.IsSetupRecipe && x.Name == name); + + if (recipe == null) { + return HttpNotFound(); + } + + var executionId = _recipeManager.Execute(recipe); + + if (string.IsNullOrEmpty(executionId)) { + Logger.Error("Error while executing recipe {0} in {1}.", name, moduleId); + + Services.Notifier.Error(T("Error while executing recipe {0} in {1}.", name, moduleId)); + + return RedirectToAction("Index"); + } + else { + return RedirectToAction("RecipeResult", new { executionId }); + } + + } + + public ActionResult RecipeResult(string executionId) { + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not allowed to view recipe file execution results."))) + return new HttpUnauthorizedResult(); + + var result = _recipeResultAccessor.GetResult(executionId); + + var viewModel = new RecipeResultViewModel() { + Result = result + }; + + return View(viewModel); + } + + + /// + /// Checks whether the given Extension is allowed for the current Tenant. + /// + private bool ExtensionIsAllowed(ExtensionDescriptor extensionDescriptor) { + return _shellSettings.Modules.Length == 0 || _shellSettings.Modules.Contains(extensionDescriptor.Id); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Module.txt b/src/Orchard.Web/Modules/Orchard.Recipes/Module.txt index b8bfc062cde..37e60333fb0 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Module.txt @@ -2,8 +2,9 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Provides Orchard Recipes. FeatureDescription: Implementation of Orchard recipes. Category: Core +Dependencies: PackagingServices diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Orchard.Recipes.csproj b/src/Orchard.Web/Modules/Orchard.Recipes/Orchard.Recipes.csproj index d7428a54f23..8b921c9b8e7 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/Orchard.Recipes.csproj +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Orchard.Recipes.csproj @@ -13,7 +13,8 @@ Properties Orchard.Recipes Orchard.Recipes - v4.5.2 + v4.8 + 7.3 false @@ -26,6 +27,9 @@ + + +
        true @@ -50,16 +54,16 @@ ..\..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll - True - - ..\..\..\packages\log4net.2.0.3\lib\net40-full\log4net.dll - True + + ..\..\..\packages\log4net.2.0.12\lib\net45\log4net.dll + + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True @@ -69,28 +73,22 @@ - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.Helpers.dll - - ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True + + ..\..\..\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll - ..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.Razor.3.2.7\lib\net45\System.Web.Razor.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Deployment.dll - ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True + ..\..\..\packages\Microsoft.AspNet.WebPages.3.2.7\lib\net45\System.Web.WebPages.Razor.dll @@ -105,7 +103,9 @@ + + @@ -120,6 +120,7 @@ + @@ -138,8 +139,9 @@ - + + @@ -147,7 +149,7 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {0e7646e8-fe8f-43c1-8799-d97860925ec4} @@ -178,7 +180,13 @@ - + + + + + + + 10.0 @@ -187,6 +195,14 @@ + + + $(ProjectDir)\..\Manifests + + + + + @@ -199,17 +215,10 @@ False True - http://orchard.codeplex.com/ + https://github.com/OrchardCMS/Orchard/ False - - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Recipes/Properties/AssemblyInfo.cs index 1846dbf2596..4eab54bbb85 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Providers/Executors/RemoveFromContentTypeStep.cs b/src/Orchard.Web/Modules/Orchard.Recipes/Providers/Executors/RemoveFromContentTypeStep.cs new file mode 100644 index 00000000000..06a7514e13f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Providers/Executors/RemoveFromContentTypeStep.cs @@ -0,0 +1,89 @@ +using System; +using System.Xml; +using Orchard.ContentManagement.MetaData; +using Orchard.ContentTypes.Events; +using Orchard.Localization; +using Orchard.Logging; +using Orchard.Recipes.Models; +using Orchard.Recipes.Services; + +namespace Orchard.Recipes.Providers.Executors { + public class RemoveFromContentTypeStep : RecipeExecutionStep { + private readonly IContentDefinitionManager _contentDefinitionManager; + private readonly IContentDefinitionEventHandler _contentDefinitionEventHandlers; + + public RemoveFromContentTypeStep(RecipeExecutionLogger logger, IContentDefinitionManager contentDefinitionManager, + IContentDefinitionEventHandler contentDefinitonEventHandlers) : base(logger) { + _contentDefinitionManager = contentDefinitionManager; + _contentDefinitionEventHandlers = contentDefinitonEventHandlers; + } + + public override string Name { + get { return "RemoveFromContentType"; } + } + + public override LocalizedString DisplayName { + get { return T("Remove From Content Type"); } + } + + public override LocalizedString Description { + get { return T("Removes a list of parts and fields from a content type."); } + } + + // + // + // + // + // + // + // + // + public override void Execute(RecipeExecutionContext context) { + foreach (var metadataElementType in context.RecipeStep.Step.Elements()) { + Logger.Debug("Processing element '{0}'.", metadataElementType.Name.LocalName); + var typeName = XmlConvert.DecodeName(metadataElementType.Name.LocalName); + + foreach (var metadataElement in metadataElementType.Elements()) { + switch (metadataElement.Name.LocalName) { + case "Parts": + foreach (var element in metadataElement.Elements()) { + var partName = XmlConvert.DecodeName(element.Name.LocalName); + + Logger.Information("Removing content part '{0}' from content type '{1}'.", partName, typeName); + try { + _contentDefinitionManager.AlterTypeDefinition(typeName, typeBuilder => typeBuilder.RemovePart(partName)); + _contentDefinitionEventHandlers.ContentPartDetached(new ContentPartDetachedContext { ContentTypeName = typeName, ContentPartName = partName }); + } + catch (Exception ex) { + Logger.Error(ex, "Error while removing content part '{0}' from content type'{1}'.", partName, typeName); + throw; + } + } + break; + + case "Fields": + foreach (var element in metadataElement.Elements()) { + var fieldName = XmlConvert.DecodeName(element.Name.LocalName); + + Logger.Information("Removing content field '{0}' from content type '{1}'.", fieldName, typeName); + try { + _contentDefinitionManager.AlterPartDefinition(typeName, typeBuilder => typeBuilder.RemoveField(fieldName)); + _contentDefinitionEventHandlers.ContentFieldDetached(new ContentFieldDetachedContext { ContentPartName = typeName, ContentFieldName = fieldName }); + } + catch (Exception ex) { + Logger.Error(ex, "Error while removing content field '{0}' from content type'{1}'.", fieldName, typeName); + throw; + } + } + break; + + default: + Logger.Warning("Unrecognized element '{0}' encountered; skipping", + metadataElement.Name.LocalName); + break; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Routes.cs b/src/Orchard.Web/Modules/Orchard.Recipes/Routes.cs index 3b4e884462e..3f195af9c92 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/Routes.cs +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Routes.cs @@ -6,14 +6,9 @@ namespace Orchard.Recipes { public class Routes : IRouteProvider { public void GetRoutes(ICollection routes) { - foreach (var routeDescriptor in GetRoutes()) - routes.Add(routeDescriptor); - } - - public IEnumerable GetRoutes() { - return new[] { - new RouteDescriptor { Priority = 5, - Route = new Route( + var routeDescriptor = new RouteDescriptor { + Priority = 5, + Route = new Route( "Recipes/Status/{executionId}", new RouteValueDictionary { {"area", "Orchard.Recipes"}, @@ -25,8 +20,9 @@ public IEnumerable GetRoutes() { {"area", "Orchard.Recipes"} }, new MvcRouteHandler()) - } - }; + }; + + routes.Add(routeDescriptor); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeHarvester.cs b/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeHarvester.cs index 0364c6b8dcb..b205c9a1041 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeHarvester.cs +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeHarvester.cs @@ -46,7 +46,7 @@ public IEnumerable HarvestRecipes(string extensionId) { private IEnumerable HarvestRecipes(ExtensionDescriptor extension) { var recipes = new List(); - + var recipeLocation = Path.Combine(extension.Location, extension.Id, "Recipes"); var recipeFiles = _webSiteFolder.ListFiles(recipeLocation, true); @@ -58,7 +58,7 @@ private IEnumerable HarvestRecipes(ExtensionDescriptor extension) { Logger.Error(ex, "Error while parsing recipe file '{0}'.", r); } }); - + return recipes; } } diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeManager.cs b/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeManager.cs index 41ae6ac9cb6..434b338503b 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeManager.cs @@ -3,6 +3,7 @@ using log4net; using Orchard.Data; using Orchard.Logging; +using Orchard.Mvc; using Orchard.Recipes.Events; using Orchard.Recipes.Models; @@ -12,17 +13,38 @@ public class RecipeManager : Component, IRecipeManager { private readonly IRecipeScheduler _recipeScheduler; private readonly IRecipeExecuteEventHandler _recipeExecuteEventHandler; private readonly IRepository _recipeStepResultRecordRepository; + private readonly IHttpContextAccessor _httpContextAccessor; public RecipeManager( IRecipeStepQueue recipeStepQueue, IRecipeScheduler recipeScheduler, IRecipeExecuteEventHandler recipeExecuteEventHandler, - IRepository recipeStepResultRecordRepository) { + IRepository recipeStepResultRecordRepository, + IHttpContextAccessor httpContextAccessor) { _recipeStepQueue = recipeStepQueue; _recipeScheduler = recipeScheduler; _recipeExecuteEventHandler = recipeExecuteEventHandler; _recipeStepResultRecordRepository = recipeStepResultRecordRepository; + _httpContextAccessor = httpContextAccessor; + + RecipeExecutionTimeout = 600; + } + + public int RecipeExecutionTimeout { + get; set; + // The public setter allows injecting this from Sites.MyTenant.Config or Sites.config, by using + // an AutoFac component: + /* + + + + + + + */ } public string Execute(Recipe recipe) { @@ -35,6 +57,12 @@ public string Execute(Recipe recipe) { return null; } + // Sets the request timeout to a configurable amount of seconds to give enough time to execute custom recipes. + var httpContext = _httpContextAccessor.Current(); + if (httpContext != null) { + httpContext.Server.ScriptTimeout = RecipeExecutionTimeout; + } + var executionId = Guid.NewGuid().ToString("n"); ThreadContext.Properties["ExecutionId"] = executionId; diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeStepExecutor.cs b/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeStepExecutor.cs index 8ec72844106..980da0aad0f 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeStepExecutor.cs +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeStepExecutor.cs @@ -5,6 +5,7 @@ using Orchard.Logging; using Orchard.Recipes.Events; using Orchard.Recipes.Models; +using Orchard.Environment.Configuration; namespace Orchard.Recipes.Services { public class RecipeStepExecutor : Component, IRecipeStepExecutor { @@ -12,17 +13,20 @@ public class RecipeStepExecutor : Component, IRecipeStepExecutor { private readonly IEnumerable _recipeHandlers; private readonly IRecipeExecuteEventHandler _recipeExecuteEventHandler; private readonly IRepository _recipeStepResultRepository; + private readonly ShellSettings _shellSettings; public RecipeStepExecutor( IRecipeStepQueue recipeStepQueue, IEnumerable recipeHandlers, IRecipeExecuteEventHandler recipeExecuteEventHandler, - IRepository recipeStepResultRepository) { + IRepository recipeStepResultRepository, + ShellSettings shellSettings) { _recipeStepQueue = recipeStepQueue; _recipeHandlers = recipeHandlers; _recipeExecuteEventHandler = recipeExecuteEventHandler; _recipeStepResultRepository = recipeStepResultRepository; + _shellSettings = shellSettings; } public bool ExecuteNextStep(string executionId) { @@ -49,16 +53,16 @@ public bool ExecuteNextStep(string executionId) { } catch (Exception ex) { UpdateStepResultRecord(executionId, nextRecipeStep.RecipeName, nextRecipeStep.Id, nextRecipeStep.Name, isSuccessful: false, errorMessage: ex.Message); - Logger.Error(ex, "Recipe execution failed because the step '{0}' failed.", nextRecipeStep.Name); + Logger.Error(ex, "Recipe execution for Tenant {0} failed because the step '{1}' failed.", _shellSettings.Name, nextRecipeStep.Name); while (_recipeStepQueue.Dequeue(executionId) != null); - var message = T("Recipe execution with ID {0} failed because the step '{1}' failed to execute. The following exception was thrown:\n{2}\nRefer to the error logs for more information.", executionId, nextRecipeStep.Name, ex.Message); + var message = T("Recipe execution with ID {0} for Tenant {1} failed because the step '{2}' failed to execute. The following exception was thrown:\n{3}\nRefer to the error logs for more information.", executionId, _shellSettings.Name , nextRecipeStep.Name, ex.Message); throw new OrchardCoreException(message); } if (!recipeContext.Executed) { - Logger.Error("Recipe execution failed because no matching handler for recipe step '{0}' was found.", recipeContext.RecipeStep.Name); + Logger.Error("Recipe execution for Tenant {0} failed because no matching handler for recipe step '{1}' was found.", _shellSettings.Name, recipeContext.RecipeStep.Name); while (_recipeStepQueue.Dequeue(executionId) != null); - var message = T("Recipe execution with ID {0} failed because no matching handler for recipe step '{1}' was found. Refer to the error logs for more information.", executionId, nextRecipeStep.Name); + var message = T("Recipe execution with ID {0} for Tenant {1} failed because no matching handler for recipe step '{2}' was found. Refer to the error logs for more information.", executionId, _shellSettings.Name, nextRecipeStep.Name); throw new OrchardCoreException(message); } diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/ViewModels/ImportResultViewModel.cs b/src/Orchard.Web/Modules/Orchard.Recipes/ViewModels/RecipeResultViewModel.cs similarity index 75% rename from src/Orchard.Web/Modules/Orchard.Recipes/ViewModels/ImportResultViewModel.cs rename to src/Orchard.Web/Modules/Orchard.Recipes/ViewModels/RecipeResultViewModel.cs index 206393f3aaa..463dddfc330 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/ViewModels/ImportResultViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Recipes/ViewModels/RecipeResultViewModel.cs @@ -1,7 +1,7 @@ using Orchard.Recipes.Models; namespace Orchard.Recipes.ViewModels { - public class ImportResultViewModel { + public class RecipeResultViewModel { public RecipeResult Result { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Modules/ViewModels/RecipesViewModel.cs b/src/Orchard.Web/Modules/Orchard.Recipes/ViewModels/RecipesViewModel.cs similarity index 53% rename from src/Orchard.Web/Modules/Orchard.Modules/ViewModels/RecipesViewModel.cs rename to src/Orchard.Web/Modules/Orchard.Recipes/ViewModels/RecipesViewModel.cs index 03dbfe1c25e..7cc782f6d35 100644 --- a/src/Orchard.Web/Modules/Orchard.Modules/ViewModels/RecipesViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Recipes/ViewModels/RecipesViewModel.cs @@ -1,14 +1,14 @@ using System.Collections.Generic; -using Orchard.Modules.Models; +using Orchard.Environment.Extensions.Models; using Orchard.Recipes.Models; -namespace Orchard.Modules.ViewModels { +namespace Orchard.Recipes.ViewModels { public class RecipesViewModel { public IEnumerable Modules { get; set; } } public class ModuleRecipesViewModel { - public ModuleEntry Module { get; set; } - public IEnumerable Recipes { get; set; } + public ExtensionDescriptor Descriptor { get; set; } + public IEnumerable Recipes { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Recipes/Views/Admin/Index.cshtml new file mode 100644 index 00000000000..9890fc7893c --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Views/Admin/Index.cshtml @@ -0,0 +1,44 @@ +@using Orchard.Utility.Extensions + +@model Orchard.Recipes.ViewModels.RecipesViewModel + +@{ + Layout.Title = T("Recipes"); +} + +@using (Html.BeginFormAntiForgeryPost()) { + if (Model.Modules.Any()) { +
          + @foreach (var module in Model.Modules.OrderBy(m => m.Descriptor.Name)) { + var descriptor = module.Descriptor; + + if (string.IsNullOrWhiteSpace(descriptor.Version)) { + descriptor.Version = "1.0"; + } + +
        • +
          +
          +

          @descriptor.Name - @T("Version: {0}", descriptor.Version)

          + + @foreach (var recipe in module.Recipes) { + if (string.IsNullOrWhiteSpace(recipe.Description)) { + recipe.Description = T("No description.").Text; + } + +
          +
          +

          @recipe.Name - @Html.ActionLink(T("Execute").Text, "Recipes", "Admin", new { area = "Orchard.Recipes", moduleId = descriptor.Id, name = recipe.Name }, new { itemprop = "UnsafeUrl" })

          +

          @recipe.Description

          +
          + } +
          +
          +
        • + } +
        + } + else { +

        @T("No modules available").Text

        + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Views/Admin/RecipeResult.cshtml b/src/Orchard.Web/Modules/Orchard.Recipes/Views/Admin/RecipeResult.cshtml new file mode 100644 index 00000000000..c2d47276063 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Views/Admin/RecipeResult.cshtml @@ -0,0 +1,41 @@ +@model Orchard.Recipes.ViewModels.RecipeResultViewModel + +@{ + Layout.Title = T("Recipe File Execution Result").ToString(); +} + +@if (Model.Result.IsSuccessful) { +
        + @T("The recipe file was successfully executed.") +
        +} +else { +
        + @T("The recipe file execution failed. Check the logs (recipe execution ID {0}) for more information.", Model.Result.ExecutionId) +
        +} + +

        @T("Recipe steps")

        + + + + + + + + + + + + @foreach (var step in Model.Result.Steps) { + + + + + + + + } + +
        @T("Recipe")@T("Step")@T("Executed")@T("Result")@T("Message")
        @(!String.IsNullOrWhiteSpace(step.RecipeName) ? step.RecipeName : T("Untitled").ToString())@step.StepName@step.IsCompleted@if (step.IsSuccessful) { @T("Successful") } else if (step.IsCompleted) { @T("Failed") }@step.ErrorMessage
        + diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Web.config b/src/Orchard.Web/Modules/Orchard.Recipes/Web.config index 76352b6dafc..8e392454df5 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Web.config @@ -7,7 +7,7 @@ - + @@ -21,37 +21,56 @@ + + + - + - + - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/packages.config b/src/Orchard.Web/Modules/Orchard.Recipes/packages.config index 22e7c11e9e8..85586378bef 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Recipes/packages.config @@ -1,9 +1,10 @@  - - - - - - - \ No newline at end of file + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs b/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs index 38ba2134b4b..c85578cd863 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs @@ -58,7 +58,7 @@ public void Remove(string key) { } public void Clear() { - Database.KeyDeleteWithPrefix(GetLocalizedKey("*")); + _connectionMultiplexer.KeyDeleteWithPrefix(GetLocalizedKey("*")); } private string GetLocalizedKey(string key) { diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Extensions/RedisDatabaseExtensions.cs b/src/Orchard.Web/Modules/Orchard.Redis/Extensions/RedisDatabaseExtensions.cs deleted file mode 100644 index 2b223a064d6..00000000000 --- a/src/Orchard.Web/Modules/Orchard.Redis/Extensions/RedisDatabaseExtensions.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using StackExchange.Redis; - -namespace Orchard.Redis.Extensions { - public static class RedisDatabaseExtensions { - - public static void KeyDeleteWithPrefix(this IDatabase database, string prefix) { - if (database == null) { - throw new ArgumentException("Database cannot be null", "database"); - } - - if (string.IsNullOrWhiteSpace(prefix)) { - throw new ArgumentException("Prefix cannot be empty", "database"); - } - - database.ScriptEvaluate(@" - local keys = redis.call('keys', ARGV[1]) - for i=1,#keys,5000 do - redis.call('del', unpack(keys, i, math.min(i+4999, #keys))) - end", values: new RedisValue[] { prefix }); - } - - public static int KeyCount(this IDatabase database, string prefix) { - if (database == null) { - throw new ArgumentException("Database cannot be null", "database"); - } - - if (string.IsNullOrWhiteSpace(prefix)) { - throw new ArgumentException("Prefix cannot be empty", "database"); - } - - var retVal = database.ScriptEvaluate("return table.getn(redis.call('keys', ARGV[1]))", values: new RedisValue[] { prefix }); - - if (retVal.IsNull) { - return 0; - } - - return (int)retVal; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Module.txt b/src/Orchard.Web/Modules/Orchard.Redis/Module.txt index ba0cc4050f1..780ec6e6a0d 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Redis/Module.txt @@ -2,8 +2,8 @@ AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net -Version: 1.10.1 -OrchardVersion: 1.9 +Version: 1.10.3 +OrchardVersion: 1.10.3 Description: Provides Redis integration with Orchard. Features: Orchard.Redis diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj b/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj index 891fb88bf8f..7cf04935819 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj +++ b/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj @@ -12,8 +12,8 @@ Properties Orchard.Redis Orchard.Redis - v4.5.2 - false + v4.8 + 7.3 4.0 @@ -25,6 +25,7 @@ +
        true @@ -48,28 +49,35 @@ false - - ..\..\..\packages\Iesi.Collections.4.0.1.4000\lib\net40\Iesi.Collections.dll - True + + ..\..\..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll + + + ..\..\..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll - - ..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - True + + ..\..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\..\..\packages\NHibernate.5.3.10\lib\net461\NHibernate.dll + + + ..\..\..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll - - ..\..\..\packages\NHibernate.4.0.1.4000\lib\net40\NHibernate.dll - True + + ..\..\..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll ..\..\..\packages\StackExchange.Redis.1.0.481\lib\net45\StackExchange.Redis.dll - True 3.5 + + @@ -91,12 +99,12 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework - false + $(MvcBuildViews) {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - false + $(MvcBuildViews) {7528BF74-25C7-4ABE-883A-443B4EEC4776} @@ -113,7 +121,7 @@ - + @@ -121,7 +129,7 @@ - + 10.0 @@ -147,7 +155,7 @@ --> - + @@ -161,10 +169,10 @@ False True - http://orchard.codeplex.com + https://github.com/OrchardCMS/Orchard False - \ No newline at end of file + diff --git a/src/Orchard.Web/Modules/Orchard.Redis/OutputCache/RedisOutputCacheStorageProvider.cs b/src/Orchard.Web/Modules/Orchard.Redis/OutputCache/RedisOutputCacheStorageProvider.cs index c740bf294c9..ca8816b7e63 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/OutputCache/RedisOutputCacheStorageProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Redis/OutputCache/RedisOutputCacheStorageProvider.cs @@ -86,7 +86,7 @@ public void RemoveAll() { return; } - Database.KeyDeleteWithPrefix(GetLocalizedKey("*")); + Database.KeyDelete(GetPrefixedKeys().Select(key => (RedisKey)key).ToArray()); } public CacheItem GetCacheItem(string key) { @@ -126,7 +126,7 @@ public int GetCacheItemsCount() { return 0; } - return Database.KeyCount(GetLocalizedKey("*")); + return GetPrefixedKeys().Count(); } /// @@ -147,19 +147,19 @@ private IEnumerable GetAllKeys() { return new string[0]; } + var prefix = GetLocalizedKey(""); + return GetPrefixedKeys().Select(x => x.Substring(prefix.Length)); + } + + private IEnumerable GetPrefixedKeys() { // prevent the same request from computing the list twice (count + list) if (_keysCache == null) { _keysCache = new HashSet(); - var prefix = GetLocalizedKey(""); - - foreach (var endPoint in _connectionMultiplexer.GetEndPoints()) { - var server = _connectionMultiplexer.GetServer(endPoint); - foreach (var key in server.Keys(pattern: GetLocalizedKey("*"))) { - _keysCache.Add(key.ToString().Substring(prefix.Length)); - } + var keys = _connectionMultiplexer.GetKeys(GetLocalizedKey("*")); + foreach (var key in keys) { + _keysCache.Add(key); } } - return _keysCache; } diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Redis/Properties/AssemblyInfo.cs index a42476ab0ca..1aa82adaa1c 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/Properties/AssemblyInfo.cs +++ b/src/Orchard.Web/Modules/Orchard.Redis/Properties/AssemblyInfo.cs @@ -32,6 +32,6 @@ // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.10.1")] -[assembly: AssemblyFileVersion("1.10.1")] +[assembly: AssemblyVersion("1.10.3")] +[assembly: AssemblyFileVersion("1.10.3")] diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Web.config b/src/Orchard.Web/Modules/Orchard.Redis/Web.config index 4c0b6467cb5..804fac07aba 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/Web.config +++ b/src/Orchard.Web/Modules/Orchard.Redis/Web.config @@ -7,7 +7,7 @@ - + @@ -22,36 +22,35 @@ - + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Redis/packages.config b/src/Orchard.Web/Modules/Orchard.Redis/packages.config index a998bafc565..15b9d28a1d6 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/packages.config +++ b/src/Orchard.Web/Modules/Orchard.Redis/packages.config @@ -1,7 +1,10 @@  - - - - - \ No newline at end of file + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Assets.json b/src/Orchard.Web/Modules/Orchard.Resources/Assets.json index ad4b81ebc7f..3dde96164d1 100644 --- a/src/Orchard.Web/Modules/Orchard.Resources/Assets.json +++ b/src/Orchard.Web/Modules/Orchard.Resources/Assets.json @@ -1,6 +1,6 @@ [ { - "inputs": [ "Assets/Js/jQuery/jquery-2.1.4.js" ], + "inputs": [ "Assets/Js/jQuery/jquery-3.3.1.js" ], "output": "Scripts/jquery.js" }, { @@ -103,23 +103,24 @@ "output": "Scripts/underscore.js" }, { - "inputs": [ "Assets/Less/Bootstrap/bootstrap.less" ], + "inputs": [ "Assets/scss/Bootstrap/bootstrap.scss" ], "output": "Styles/bootstrap.css" }, { - "inputs": [ - "Assets/Js/Bootstrap/affix.js", + "inputs": [ "Assets/Js/Bootstrap/alert.js", "Assets/Js/Bootstrap/button.js", "Assets/Js/Bootstrap/carousel.js", "Assets/Js/Bootstrap/collapse.js", "Assets/Js/Bootstrap/dropdown.js", + "Assets/Js/Bootstrap/index.js", "Assets/Js/Bootstrap/modal.js", "Assets/Js/Bootstrap/tooltip.js", "Assets/Js/Bootstrap/popover.js", "Assets/Js/Bootstrap/scrollspy.js", - "Assets/Js/Bootstrap/tab.js", - "Assets/Js/Bootstrap/transition.js" + "Assets/Js/Bootstrap/tab.js", + "Assets/Js/Bootstrap/toast.js", + "Assets/Js/Bootstrap/util.js" ], "output": "Scripts/bootstrap.js" }, diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Css/jQueryUI/jquery-ui.css b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Css/jQueryUI/jquery-ui.css index 8e3f4b87776..04200727faa 100644 --- a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Css/jQueryUI/jquery-ui.css +++ b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Css/jQueryUI/jquery-ui.css @@ -1,9 +1,13 @@ -/*! jQuery UI - v1.11.4 - 2016-02-09 +/*! jQuery UI - v1.13.2 - 2024-03-09 * http://jqueryui.com -* Includes: core.css, draggable.css, resizable.css, selectable.css, sortable.css, accordion.css, autocomplete.css, button.css, datepicker.css, dialog.css, menu.css, progressbar.css, selectmenu.css, slider.css, spinner.css, tabs.css, tooltip.css, theme.css -* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px +* Includes: draggable.css, core.css, resizable.css, selectable.css, sortable.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, progressbar.css, selectmenu.css, slider.css, spinner.css, tabs.css, tooltip.css, theme.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?scope=&folderName=base&cornerRadiusShadow=8px&offsetLeftShadow=0px&offsetTopShadow=0px&thicknessShadow=5px&opacityShadow=30&bgImgOpacityShadow=0&bgTextureShadow=flat&bgColorShadow=666666&opacityOverlay=30&bgImgOpacityOverlay=0&bgTextureOverlay=flat&bgColorOverlay=aaaaaa&iconColorError=cc0000&fcError=5f3f3f&borderColorError=f1a899&bgTextureError=flat&bgColorError=fddfdf&iconColorHighlight=777620&fcHighlight=777620&borderColorHighlight=dad55e&bgTextureHighlight=flat&bgColorHighlight=fffa90&iconColorActive=ffffff&fcActive=ffffff&borderColorActive=003eff&bgTextureActive=flat&bgColorActive=007fff&iconColorHover=555555&fcHover=2b2b2b&borderColorHover=cccccc&bgTextureHover=flat&bgColorHover=ededed&iconColorDefault=777777&fcDefault=454545&borderColorDefault=c5c5c5&bgTextureDefault=flat&bgColorDefault=f6f6f6&iconColorContent=444444&fcContent=333333&borderColorContent=dddddd&bgTextureContent=flat&bgColorContent=ffffff&iconColorHeader=444444&fcHeader=333333&borderColorHeader=dddddd&bgTextureHeader=flat&bgColorHeader=e9e9e9&cornerRadius=3px&fwDefault=normal&fsDefault=1em&ffDefault=Arial%2CHelvetica%2Csans-serif * Copyright jQuery Foundation and other contributors; Licensed MIT */ +.ui-draggable-handle { + -ms-touch-action: none; + touch-action: none; +} /* Layout helpers ----------------------------------*/ .ui-helper-hidden { @@ -38,9 +42,6 @@ .ui-helper-clearfix:after { clear: both; } -.ui-helper-clearfix { - min-height: 0; /* support: IE7 */ -} .ui-helper-zfix { width: 100%; height: 100%; @@ -48,7 +49,7 @@ left: 0; position: absolute; opacity: 0; - filter:Alpha(Opacity=0); /* support: IE8 */ + -ms-filter: "alpha(opacity=0)"; /* support: IE8 */ } .ui-front { @@ -60,20 +61,27 @@ ----------------------------------*/ .ui-state-disabled { cursor: default !important; + pointer-events: none; } /* Icons ----------------------------------*/ - -/* states and images */ .ui-icon { - display: block; + display: inline-block; + vertical-align: middle; + margin-top: -.25em; + position: relative; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } +.ui-widget-icon-block { + left: 50%; + margin-left: -8px; + display: block; +} /* Misc visuals ----------------------------------*/ @@ -86,10 +94,6 @@ width: 100%; height: 100%; } -.ui-draggable-handle { - -ms-touch-action: none; - touch-action: none; -} .ui-resizable { position: relative; } @@ -179,21 +183,8 @@ position: relative; margin: 2px 0 0 0; padding: .5em .5em .5em .7em; - min-height: 0; /* support: IE7 */ font-size: 100%; } -.ui-accordion .ui-accordion-icons { - padding-left: 2.2em; -} -.ui-accordion .ui-accordion-icons .ui-accordion-icons { - padding-left: 2.2em; -} -.ui-accordion .ui-accordion-header .ui-accordion-header-icon { - position: absolute; - left: .5em; - top: 50%; - margin-top: -8px; -} .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; @@ -205,17 +196,78 @@ left: 0; cursor: default; } +.ui-menu { + list-style: none; + padding: 0; + margin: 0; + display: block; + outline: 0; +} +.ui-menu .ui-menu { + position: absolute; +} +.ui-menu .ui-menu-item { + margin: 0; + cursor: pointer; + /* support: IE10, see #8844 */ + list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"); +} +.ui-menu .ui-menu-item-wrapper { + position: relative; + padding: 3px 1em 3px .4em; +} +.ui-menu .ui-menu-divider { + margin: 5px 0; + height: 0; + font-size: 0; + line-height: 0; + border-width: 1px 0 0 0; +} +.ui-menu .ui-state-focus, +.ui-menu .ui-state-active { + margin: -1px; +} + +/* icon support */ +.ui-menu-icons { + position: relative; +} +.ui-menu-icons .ui-menu-item-wrapper { + padding-left: 2em; +} + +/* left-aligned */ +.ui-menu .ui-icon { + position: absolute; + top: 0; + bottom: 0; + left: .2em; + margin: auto 0; +} + +/* right-aligned */ +.ui-menu .ui-menu-icon { + left: auto; + right: 0; +} .ui-button { + padding: .4em 1em; display: inline-block; position: relative; - padding: 0; line-height: normal; margin-right: .1em; cursor: pointer; vertical-align: middle; text-align: center; - overflow: visible; /* removes extra width in IE */ + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + /* Support: IE <= 11 */ + overflow: visible; } + .ui-button, .ui-button:link, .ui-button:visited, @@ -223,91 +275,129 @@ .ui-button:active { text-decoration: none; } + /* to make room for the icon, a width needs to be set here */ .ui-button-icon-only { - width: 2.2em; -} -/* button elements seem to need a little more width */ -button.ui-button-icon-only { - width: 2.4em; + width: 2em; + box-sizing: border-box; + text-indent: -9999px; + white-space: nowrap; } -.ui-button-icons-only { - width: 3.4em; + +/* no icon support for input elements */ +input.ui-button.ui-button-icon-only { + text-indent: 0; } -button.ui-button-icons-only { - width: 3.7em; + +/* button icon element(s) */ +.ui-button-icon-only .ui-icon { + position: absolute; + top: 50%; + left: 50%; + margin-top: -8px; + margin-left: -8px; } -/* button text element */ -.ui-button .ui-button-text { - display: block; - line-height: normal; +.ui-button.ui-icon-notext .ui-icon { + padding: 0; + width: 2.1em; + height: 2.1em; + text-indent: -9999px; + white-space: nowrap; + } -.ui-button-text-only .ui-button-text { + +input.ui-button.ui-icon-notext .ui-icon { + width: auto; + height: auto; + text-indent: 0; + white-space: normal; padding: .4em 1em; } -.ui-button-icon-only .ui-button-text, -.ui-button-icons-only .ui-button-text { - padding: .4em; - text-indent: -9999999px; + +/* workarounds */ +/* Support: Firefox 5 - 40 */ +input.ui-button::-moz-focus-inner, +button.ui-button::-moz-focus-inner { + border: 0; + padding: 0; } -.ui-button-text-icon-primary .ui-button-text, -.ui-button-text-icons .ui-button-text { - padding: .4em 1em .4em 2.1em; +.ui-controlgroup { + vertical-align: middle; + display: inline-block; +} +.ui-controlgroup > .ui-controlgroup-item { + float: left; + margin-left: 0; + margin-right: 0; } -.ui-button-text-icon-secondary .ui-button-text, -.ui-button-text-icons .ui-button-text { - padding: .4em 2.1em .4em 1em; +.ui-controlgroup > .ui-controlgroup-item:focus, +.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus { + z-index: 9999; } -.ui-button-text-icons .ui-button-text { - padding-left: 2.1em; - padding-right: 2.1em; +.ui-controlgroup-vertical > .ui-controlgroup-item { + display: block; + float: none; + width: 100%; + margin-top: 0; + margin-bottom: 0; + text-align: left; } -/* no icon support for input elements, provide padding by default */ -input.ui-button { +.ui-controlgroup-vertical .ui-controlgroup-item { + box-sizing: border-box; +} +.ui-controlgroup .ui-controlgroup-label { padding: .4em 1em; } - -/* button icon element(s) */ -.ui-button-icon-only .ui-icon, -.ui-button-text-icon-primary .ui-icon, -.ui-button-text-icon-secondary .ui-icon, -.ui-button-text-icons .ui-icon, -.ui-button-icons-only .ui-icon { - position: absolute; - top: 50%; - margin-top: -8px; +.ui-controlgroup .ui-controlgroup-label span { + font-size: 80%; } -.ui-button-icon-only .ui-icon { - left: 50%; - margin-left: -8px; +.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item { + border-left: none; } -.ui-button-text-icon-primary .ui-button-icon-primary, -.ui-button-text-icons .ui-button-icon-primary, -.ui-button-icons-only .ui-button-icon-primary { - left: .5em; +.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item { + border-top: none; +} +.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content { + border-right: none; } -.ui-button-text-icon-secondary .ui-button-icon-secondary, -.ui-button-text-icons .ui-button-icon-secondary, -.ui-button-icons-only .ui-button-icon-secondary { - right: .5em; +.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content { + border-bottom: none; } -/* button sets */ -.ui-buttonset { - margin-right: 7px; +/* Spinner specific style fixes */ +.ui-controlgroup-vertical .ui-spinner-input { + + /* Support: IE8 only, Android < 4.4 only */ + width: 75%; + width: calc( 100% - 2.4em ); } -.ui-buttonset .ui-button { - margin-left: 0; - margin-right: -.3em; +.ui-controlgroup-vertical .ui-spinner .ui-spinner-up { + border-top-style: solid; } -/* workarounds */ -/* reset extra padding in Firefox, see h5bp.com/l */ -input.ui-button::-moz-focus-inner, -button.ui-button::-moz-focus-inner { - border: 0; - padding: 0; +.ui-checkboxradio-label .ui-icon-background { + box-shadow: inset 1px 1px 1px #ccc; + border-radius: .12em; + border: none; +} +.ui-checkboxradio-radio-label .ui-icon-background { + width: 16px; + height: 16px; + border-radius: 1em; + overflow: visible; + border: none; +} +.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon, +.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon { + background-image: none; + width: 8px; + height: 8px; + border-width: 4px; + border-style: solid; +} +.ui-checkboxradio-disabled { + pointer-events: none; } .ui-datepicker { width: 17em; @@ -474,8 +564,17 @@ button.ui-button::-moz-focus-inner { border-right-width: 0; border-left-width: 1px; } -.ui-dialog { + +/* Icons */ +.ui-datepicker .ui-icon { + display: block; + text-indent: -99999px; overflow: hidden; + background-repeat: no-repeat; + left: .5em; + top: .3em; +} +.ui-dialog { position: absolute; top: 0; left: 0; @@ -524,68 +623,47 @@ button.ui-button::-moz-focus-inner { margin: .5em .4em .5em 0; cursor: pointer; } -.ui-dialog .ui-resizable-se { - width: 12px; - height: 12px; - right: -5px; - bottom: -5px; - background-position: 16px 16px; -} -.ui-draggable .ui-dialog-titlebar { - cursor: move; +.ui-dialog .ui-resizable-n { + height: 2px; + top: 0; } -.ui-menu { - list-style: none; - padding: 0; - margin: 0; - display: block; - outline: none; +.ui-dialog .ui-resizable-e { + width: 2px; + right: 0; } -.ui-menu .ui-menu { - position: absolute; +.ui-dialog .ui-resizable-s { + height: 2px; + bottom: 0; } -.ui-menu .ui-menu-item { - position: relative; - margin: 0; - padding: 3px 1em 3px .4em; - cursor: pointer; - min-height: 0; /* support: IE7 */ - /* support: IE10, see #8844 */ - list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"); +.ui-dialog .ui-resizable-w { + width: 2px; + left: 0; } -.ui-menu .ui-menu-divider { - margin: 5px 0; - height: 0; - font-size: 0; - line-height: 0; - border-width: 1px 0 0 0; +.ui-dialog .ui-resizable-se, +.ui-dialog .ui-resizable-sw, +.ui-dialog .ui-resizable-ne, +.ui-dialog .ui-resizable-nw { + width: 7px; + height: 7px; } -.ui-menu .ui-state-focus, -.ui-menu .ui-state-active { - margin: -1px; +.ui-dialog .ui-resizable-se { + right: 0; + bottom: 0; } - -/* icon support */ -.ui-menu-icons { - position: relative; +.ui-dialog .ui-resizable-sw { + left: 0; + bottom: 0; } -.ui-menu-icons .ui-menu-item { - padding-left: 2em; +.ui-dialog .ui-resizable-ne { + right: 0; + top: 0; } - -/* left-aligned */ -.ui-menu .ui-icon { - position: absolute; +.ui-dialog .ui-resizable-nw { + left: 0; top: 0; - bottom: 0; - left: .2em; - margin: auto 0; } - -/* right-aligned */ -.ui-menu .ui-menu-icon { - left: auto; - right: 0; +.ui-draggable .ui-dialog-titlebar { + cursor: move; } .ui-progressbar { height: 2em; @@ -599,7 +677,7 @@ button.ui-button::-moz-focus-inner { .ui-progressbar .ui-progressbar-overlay { background: url("data:image/gif;base64,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"); height: 100%; - filter: alpha(opacity=25); /* support: IE8 */ + -ms-filter: "alpha(opacity=25)"; /* support: IE8 */ opacity: 0.25; } .ui-progressbar-indeterminate .ui-progressbar-value { @@ -615,7 +693,6 @@ button.ui-button::-moz-focus-inner { } .ui-selectmenu-menu .ui-menu { overflow: auto; - /* Support: IE7 */ overflow-x: hidden; padding-bottom: 1px; } @@ -631,28 +708,20 @@ button.ui-button::-moz-focus-inner { .ui-selectmenu-open { display: block; } -.ui-selectmenu-button { - display: inline-block; - overflow: hidden; - position: relative; - text-decoration: none; - cursor: pointer; -} -.ui-selectmenu-button span.ui-icon { - right: 0.5em; - left: auto; - margin-top: -8px; - position: absolute; - top: 50%; -} -.ui-selectmenu-button span.ui-selectmenu-text { - text-align: left; - padding: 0.4em 2.1em 0.4em 1em; +.ui-selectmenu-text { display: block; - line-height: 1.4; + margin-right: 20px; overflow: hidden; text-overflow: ellipsis; +} +.ui-selectmenu-button.ui-button { + text-align: left; white-space: nowrap; + width: 14em; +} +.ui-selectmenu-icon.ui-icon { + float: right; + margin-top: 0; } .ui-slider { position: relative; @@ -663,7 +732,7 @@ button.ui-button::-moz-focus-inner { z-index: 2; width: 1.2em; height: 1.2em; - cursor: default; + cursor: pointer; -ms-touch-action: none; touch-action: none; } @@ -730,14 +799,14 @@ button.ui-button::-moz-focus-inner { border: none; background: none; color: inherit; - padding: 0; + padding: .222em 0; margin: .2em 0; vertical-align: middle; margin-left: .4em; - margin-right: 22px; + margin-right: 2em; } .ui-spinner-button { - width: 16px; + width: 1.6em; height: 50%; font-size: .5em; padding: 0; @@ -751,16 +820,9 @@ button.ui-button::-moz-focus-inner { } /* more specificity required here to override default borders */ .ui-spinner a.ui-spinner-button { - border-top: none; - border-bottom: none; - border-right: none; -} -/* vertically center icon */ -.ui-spinner .ui-icon { - position: absolute; - margin-top: -8px; - top: 50%; - left: 0; + border-top-style: none; + border-bottom-style: none; + border-right-style: none; } .ui-spinner-up { top: 0; @@ -768,12 +830,6 @@ button.ui-button::-moz-focus-inner { .ui-spinner-down { bottom: 0; } - -/* TR overrides */ -.ui-spinner .ui-icon-triangle-1-s { - /* need to fix icons sprite */ - background-position: -65px -16px; -} .ui-tabs { position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ padding: .2em; @@ -820,8 +876,6 @@ button.ui-button::-moz-focus-inner { position: absolute; z-index: 9999; max-width: 300px; - -webkit-box-shadow: 0 0 5px #aaa; - box-shadow: 0 0 5px #aaa; } body .ui-tooltip { border-width: 2px; @@ -830,8 +884,8 @@ body .ui-tooltip { /* Component containers ----------------------------------*/ .ui-widget { - font-family: Verdana,Arial,sans-serif; - font-size: 1.1em; + font-family: Arial,Helvetica,sans-serif; + font-size: 1em; } .ui-widget .ui-widget { font-size: 1em; @@ -840,41 +894,54 @@ body .ui-tooltip { .ui-widget select, .ui-widget textarea, .ui-widget button { - font-family: Verdana,Arial,sans-serif; + font-family: Arial,Helvetica,sans-serif; font-size: 1em; } +.ui-widget.ui-widget-content { + border: 1px solid #c5c5c5; +} .ui-widget-content { - border: 1px solid #aaaaaa; + border: 1px solid #dddddd; background: #ffffff; - color: #222222; + color: #333333; } .ui-widget-content a { - color: #222222; + color: #333333; } .ui-widget-header { - border: 1px solid #aaaaaa; - background: #cccccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x; - color: #222222; + border: 1px solid #dddddd; + background: #e9e9e9; + color: #333333; font-weight: bold; } .ui-widget-header a { - color: #222222; + color: #333333; } /* Interaction states ----------------------------------*/ .ui-state-default, .ui-widget-content .ui-state-default, -.ui-widget-header .ui-state-default { - border: 1px solid #d3d3d3; - background: #e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x; +.ui-widget-header .ui-state-default, +.ui-button, + +/* We use html here because we need a greater specificity to make sure disabled +works properly when clicked or hovered */ +html .ui-button.ui-state-disabled:hover, +html .ui-button.ui-state-disabled:active { + border: 1px solid #c5c5c5; + background: #f6f6f6; font-weight: normal; - color: #555555; + color: #454545; } .ui-state-default a, .ui-state-default a:link, -.ui-state-default a:visited { - color: #555555; +.ui-state-default a:visited, +a.ui-button, +a:link.ui-button, +a:visited.ui-button, +.ui-button { + color: #454545; text-decoration: none; } .ui-state-hover, @@ -882,11 +949,13 @@ body .ui-tooltip { .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, -.ui-widget-header .ui-state-focus { - border: 1px solid #999999; - background: #dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x; +.ui-widget-header .ui-state-focus, +.ui-button:hover, +.ui-button:focus { + border: 1px solid #cccccc; + background: #ededed; font-weight: normal; - color: #212121; + color: #2b2b2b; } .ui-state-hover a, .ui-state-hover a:hover, @@ -895,22 +964,36 @@ body .ui-tooltip { .ui-state-focus a, .ui-state-focus a:hover, .ui-state-focus a:link, -.ui-state-focus a:visited { - color: #212121; +.ui-state-focus a:visited, +a.ui-button:hover, +a.ui-button:focus { + color: #2b2b2b; text-decoration: none; } + +.ui-visual-focus { + box-shadow: 0 0 3px 1px rgb(94, 158, 214); +} .ui-state-active, .ui-widget-content .ui-state-active, -.ui-widget-header .ui-state-active { - border: 1px solid #aaaaaa; - background: #ffffff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x; +.ui-widget-header .ui-state-active, +a.ui-button:active, +.ui-button:active, +.ui-button.ui-state-active:hover { + border: 1px solid #003eff; + background: #007fff; font-weight: normal; - color: #212121; + color: #ffffff; +} +.ui-icon-background, +.ui-state-active .ui-icon-background { + border: #003eff; + background-color: #ffffff; } .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { - color: #212121; + color: #ffffff; text-decoration: none; } @@ -919,31 +1002,35 @@ body .ui-tooltip { .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight { - border: 1px solid #fcefa1; - background: #fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x; - color: #363636; + border: 1px solid #dad55e; + background: #fffa90; + color: #777620; +} +.ui-state-checked { + border: 1px solid #dad55e; + background: #fffa90; } .ui-state-highlight a, .ui-widget-content .ui-state-highlight a, .ui-widget-header .ui-state-highlight a { - color: #363636; + color: #777620; } .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error { - border: 1px solid #cd0a0a; - background: #fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x; - color: #cd0a0a; + border: 1px solid #f1a899; + background: #fddfdf; + color: #5f3f3f; } .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { - color: #cd0a0a; + color: #5f3f3f; } .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { - color: #cd0a0a; + color: #5f3f3f; } .ui-priority-primary, .ui-widget-content .ui-priority-primary, @@ -954,18 +1041,18 @@ body .ui-tooltip { .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; - filter:Alpha(Opacity=70); /* support: IE8 */ + -ms-filter: "alpha(opacity=70)"; /* support: IE8 */ font-weight: normal; } .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; - filter:Alpha(Opacity=35); /* support: IE8 */ + -ms-filter: "alpha(opacity=35)"; /* support: IE8 */ background-image: none; } .ui-state-disabled .ui-icon { - filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */ + -ms-filter: "alpha(opacity=35)"; /* support: IE8 - See #6059 */ } /* Icons @@ -978,46 +1065,53 @@ body .ui-tooltip { } .ui-icon, .ui-widget-content .ui-icon { - background-image: url("images/ui-icons_222222_256x240.png"); + background-image: url("images/ui-icons_444444_256x240.png"); } .ui-widget-header .ui-icon { - background-image: url("images/ui-icons_222222_256x240.png"); -} -.ui-state-default .ui-icon { - background-image: url("images/ui-icons_888888_256x240.png"); + background-image: url("images/ui-icons_444444_256x240.png"); } .ui-state-hover .ui-icon, -.ui-state-focus .ui-icon { - background-image: url("images/ui-icons_454545_256x240.png"); +.ui-state-focus .ui-icon, +.ui-button:hover .ui-icon, +.ui-button:focus .ui-icon { + background-image: url("images/ui-icons_555555_256x240.png"); } -.ui-state-active .ui-icon { - background-image: url("images/ui-icons_454545_256x240.png"); +.ui-state-active .ui-icon, +.ui-button:active .ui-icon { + background-image: url("images/ui-icons_ffffff_256x240.png"); } -.ui-state-highlight .ui-icon { - background-image: url("images/ui-icons_2e83ff_256x240.png"); +.ui-state-highlight .ui-icon, +.ui-button .ui-state-highlight.ui-icon { + background-image: url("images/ui-icons_777620_256x240.png"); } .ui-state-error .ui-icon, .ui-state-error-text .ui-icon { - background-image: url("images/ui-icons_cd0a0a_256x240.png"); + background-image: url("images/ui-icons_cc0000_256x240.png"); +} +.ui-button .ui-icon { + background-image: url("images/ui-icons_777777_256x240.png"); } /* positioning */ -.ui-icon-blank { background-position: 16px 16px; } -.ui-icon-carat-1-n { background-position: 0 0; } -.ui-icon-carat-1-ne { background-position: -16px 0; } -.ui-icon-carat-1-e { background-position: -32px 0; } -.ui-icon-carat-1-se { background-position: -48px 0; } -.ui-icon-carat-1-s { background-position: -64px 0; } -.ui-icon-carat-1-sw { background-position: -80px 0; } -.ui-icon-carat-1-w { background-position: -96px 0; } -.ui-icon-carat-1-nw { background-position: -112px 0; } -.ui-icon-carat-2-n-s { background-position: -128px 0; } -.ui-icon-carat-2-e-w { background-position: -144px 0; } +/* Three classes needed to override `.ui-button:hover .ui-icon` */ +.ui-icon-blank.ui-icon-blank.ui-icon-blank { + background-image: none; +} +.ui-icon-caret-1-n { background-position: 0 0; } +.ui-icon-caret-1-ne { background-position: -16px 0; } +.ui-icon-caret-1-e { background-position: -32px 0; } +.ui-icon-caret-1-se { background-position: -48px 0; } +.ui-icon-caret-1-s { background-position: -65px 0; } +.ui-icon-caret-1-sw { background-position: -80px 0; } +.ui-icon-caret-1-w { background-position: -96px 0; } +.ui-icon-caret-1-nw { background-position: -112px 0; } +.ui-icon-caret-2-n-s { background-position: -128px 0; } +.ui-icon-caret-2-e-w { background-position: -144px 0; } .ui-icon-triangle-1-n { background-position: 0 -16px; } .ui-icon-triangle-1-ne { background-position: -16px -16px; } .ui-icon-triangle-1-e { background-position: -32px -16px; } .ui-icon-triangle-1-se { background-position: -48px -16px; } -.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-s { background-position: -65px -16px; } .ui-icon-triangle-1-sw { background-position: -80px -16px; } .ui-icon-triangle-1-w { background-position: -96px -16px; } .ui-icon-triangle-1-nw { background-position: -112px -16px; } @@ -1027,7 +1121,7 @@ body .ui-tooltip { .ui-icon-arrow-1-ne { background-position: -16px -32px; } .ui-icon-arrow-1-e { background-position: -32px -32px; } .ui-icon-arrow-1-se { background-position: -48px -32px; } -.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-s { background-position: -65px -32px; } .ui-icon-arrow-1-sw { background-position: -80px -32px; } .ui-icon-arrow-1-w { background-position: -96px -32px; } .ui-icon-arrow-1-nw { background-position: -112px -32px; } @@ -1039,7 +1133,7 @@ body .ui-tooltip { .ui-icon-arrowstop-1-e { background-position: -208px -32px; } .ui-icon-arrowstop-1-s { background-position: -224px -32px; } .ui-icon-arrowstop-1-w { background-position: -240px -32px; } -.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-n { background-position: 1px -48px; } .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } .ui-icon-arrowthick-1-e { background-position: -32px -48px; } .ui-icon-arrowthick-1-se { background-position: -48px -48px; } @@ -1188,38 +1282,34 @@ body .ui-tooltip { .ui-corner-top, .ui-corner-left, .ui-corner-tl { - border-top-left-radius: 4px; + border-top-left-radius: 3px; } .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { - border-top-right-radius: 4px; + border-top-right-radius: 3px; } .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { - border-bottom-left-radius: 4px; + border-bottom-left-radius: 3px; } .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { - border-bottom-right-radius: 4px; + border-bottom-right-radius: 3px; } /* Overlays */ .ui-widget-overlay { background: #aaaaaa; opacity: .3; - filter: Alpha(Opacity=30); /* support: IE8 */ + -ms-filter: Alpha(Opacity=30); /* support: IE8 */ } .ui-widget-shadow { - margin: -8px 0 0 -8px; - padding: 8px; - background: #aaaaaa; - opacity: .3; - filter: Alpha(Opacity=30); /* support: IE8 */ - border-radius: 8px; + -webkit-box-shadow: 0px 0px 5px #666666; + box-shadow: 0px 0px 5px #666666; } diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Css/jQueryUI/jquery-ui.structure.css b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Css/jQueryUI/jquery-ui.structure.css index 8184e152df2..c9a018d70e5 100644 --- a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Css/jQueryUI/jquery-ui.structure.css +++ b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Css/jQueryUI/jquery-ui.structure.css @@ -1,5 +1,5 @@ /*! - * jQuery UI CSS Framework 1.11.4 + * jQuery UI CSS Framework 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -8,7 +8,10 @@ * * http://api.jqueryui.com/category/theming/ */ - +.ui-draggable-handle { + -ms-touch-action: none; + touch-action: none; +} /* Layout helpers ----------------------------------*/ .ui-helper-hidden { @@ -43,9 +46,6 @@ .ui-helper-clearfix:after { clear: both; } -.ui-helper-clearfix { - min-height: 0; /* support: IE7 */ -} .ui-helper-zfix { width: 100%; height: 100%; @@ -53,7 +53,7 @@ left: 0; position: absolute; opacity: 0; - filter:Alpha(Opacity=0); /* support: IE8 */ + -ms-filter: "alpha(opacity=0)"; /* support: IE8 */ } .ui-front { @@ -65,20 +65,27 @@ ----------------------------------*/ .ui-state-disabled { cursor: default !important; + pointer-events: none; } /* Icons ----------------------------------*/ - -/* states and images */ .ui-icon { - display: block; + display: inline-block; + vertical-align: middle; + margin-top: -.25em; + position: relative; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } +.ui-widget-icon-block { + left: 50%; + margin-left: -8px; + display: block; +} /* Misc visuals ----------------------------------*/ @@ -91,10 +98,6 @@ width: 100%; height: 100%; } -.ui-draggable-handle { - -ms-touch-action: none; - touch-action: none; -} .ui-resizable { position: relative; } @@ -184,21 +187,8 @@ position: relative; margin: 2px 0 0 0; padding: .5em .5em .5em .7em; - min-height: 0; /* support: IE7 */ font-size: 100%; } -.ui-accordion .ui-accordion-icons { - padding-left: 2.2em; -} -.ui-accordion .ui-accordion-icons .ui-accordion-icons { - padding-left: 2.2em; -} -.ui-accordion .ui-accordion-header .ui-accordion-header-icon { - position: absolute; - left: .5em; - top: 50%; - margin-top: -8px; -} .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; @@ -210,17 +200,78 @@ left: 0; cursor: default; } +.ui-menu { + list-style: none; + padding: 0; + margin: 0; + display: block; + outline: 0; +} +.ui-menu .ui-menu { + position: absolute; +} +.ui-menu .ui-menu-item { + margin: 0; + cursor: pointer; + /* support: IE10, see #8844 */ + list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"); +} +.ui-menu .ui-menu-item-wrapper { + position: relative; + padding: 3px 1em 3px .4em; +} +.ui-menu .ui-menu-divider { + margin: 5px 0; + height: 0; + font-size: 0; + line-height: 0; + border-width: 1px 0 0 0; +} +.ui-menu .ui-state-focus, +.ui-menu .ui-state-active { + margin: -1px; +} + +/* icon support */ +.ui-menu-icons { + position: relative; +} +.ui-menu-icons .ui-menu-item-wrapper { + padding-left: 2em; +} + +/* left-aligned */ +.ui-menu .ui-icon { + position: absolute; + top: 0; + bottom: 0; + left: .2em; + margin: auto 0; +} + +/* right-aligned */ +.ui-menu .ui-menu-icon { + left: auto; + right: 0; +} .ui-button { + padding: .4em 1em; display: inline-block; position: relative; - padding: 0; line-height: normal; margin-right: .1em; cursor: pointer; vertical-align: middle; text-align: center; - overflow: visible; /* removes extra width in IE */ + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + /* Support: IE <= 11 */ + overflow: visible; } + .ui-button, .ui-button:link, .ui-button:visited, @@ -228,91 +279,129 @@ .ui-button:active { text-decoration: none; } + /* to make room for the icon, a width needs to be set here */ .ui-button-icon-only { - width: 2.2em; -} -/* button elements seem to need a little more width */ -button.ui-button-icon-only { - width: 2.4em; + width: 2em; + box-sizing: border-box; + text-indent: -9999px; + white-space: nowrap; } -.ui-button-icons-only { - width: 3.4em; + +/* no icon support for input elements */ +input.ui-button.ui-button-icon-only { + text-indent: 0; } -button.ui-button-icons-only { - width: 3.7em; + +/* button icon element(s) */ +.ui-button-icon-only .ui-icon { + position: absolute; + top: 50%; + left: 50%; + margin-top: -8px; + margin-left: -8px; } -/* button text element */ -.ui-button .ui-button-text { - display: block; - line-height: normal; +.ui-button.ui-icon-notext .ui-icon { + padding: 0; + width: 2.1em; + height: 2.1em; + text-indent: -9999px; + white-space: nowrap; + } -.ui-button-text-only .ui-button-text { + +input.ui-button.ui-icon-notext .ui-icon { + width: auto; + height: auto; + text-indent: 0; + white-space: normal; padding: .4em 1em; } -.ui-button-icon-only .ui-button-text, -.ui-button-icons-only .ui-button-text { - padding: .4em; - text-indent: -9999999px; + +/* workarounds */ +/* Support: Firefox 5 - 40 */ +input.ui-button::-moz-focus-inner, +button.ui-button::-moz-focus-inner { + border: 0; + padding: 0; } -.ui-button-text-icon-primary .ui-button-text, -.ui-button-text-icons .ui-button-text { - padding: .4em 1em .4em 2.1em; +.ui-controlgroup { + vertical-align: middle; + display: inline-block; +} +.ui-controlgroup > .ui-controlgroup-item { + float: left; + margin-left: 0; + margin-right: 0; } -.ui-button-text-icon-secondary .ui-button-text, -.ui-button-text-icons .ui-button-text { - padding: .4em 2.1em .4em 1em; +.ui-controlgroup > .ui-controlgroup-item:focus, +.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus { + z-index: 9999; } -.ui-button-text-icons .ui-button-text { - padding-left: 2.1em; - padding-right: 2.1em; +.ui-controlgroup-vertical > .ui-controlgroup-item { + display: block; + float: none; + width: 100%; + margin-top: 0; + margin-bottom: 0; + text-align: left; } -/* no icon support for input elements, provide padding by default */ -input.ui-button { +.ui-controlgroup-vertical .ui-controlgroup-item { + box-sizing: border-box; +} +.ui-controlgroup .ui-controlgroup-label { padding: .4em 1em; } - -/* button icon element(s) */ -.ui-button-icon-only .ui-icon, -.ui-button-text-icon-primary .ui-icon, -.ui-button-text-icon-secondary .ui-icon, -.ui-button-text-icons .ui-icon, -.ui-button-icons-only .ui-icon { - position: absolute; - top: 50%; - margin-top: -8px; +.ui-controlgroup .ui-controlgroup-label span { + font-size: 80%; } -.ui-button-icon-only .ui-icon { - left: 50%; - margin-left: -8px; +.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item { + border-left: none; } -.ui-button-text-icon-primary .ui-button-icon-primary, -.ui-button-text-icons .ui-button-icon-primary, -.ui-button-icons-only .ui-button-icon-primary { - left: .5em; +.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item { + border-top: none; } -.ui-button-text-icon-secondary .ui-button-icon-secondary, -.ui-button-text-icons .ui-button-icon-secondary, -.ui-button-icons-only .ui-button-icon-secondary { - right: .5em; +.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content { + border-right: none; +} +.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content { + border-bottom: none; } -/* button sets */ -.ui-buttonset { - margin-right: 7px; +/* Spinner specific style fixes */ +.ui-controlgroup-vertical .ui-spinner-input { + + /* Support: IE8 only, Android < 4.4 only */ + width: 75%; + width: calc( 100% - 2.4em ); } -.ui-buttonset .ui-button { - margin-left: 0; - margin-right: -.3em; +.ui-controlgroup-vertical .ui-spinner .ui-spinner-up { + border-top-style: solid; } -/* workarounds */ -/* reset extra padding in Firefox, see h5bp.com/l */ -input.ui-button::-moz-focus-inner, -button.ui-button::-moz-focus-inner { - border: 0; - padding: 0; +.ui-checkboxradio-label .ui-icon-background { + box-shadow: inset 1px 1px 1px #ccc; + border-radius: .12em; + border: none; +} +.ui-checkboxradio-radio-label .ui-icon-background { + width: 16px; + height: 16px; + border-radius: 1em; + overflow: visible; + border: none; +} +.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon, +.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon { + background-image: none; + width: 8px; + height: 8px; + border-width: 4px; + border-style: solid; +} +.ui-checkboxradio-disabled { + pointer-events: none; } .ui-datepicker { width: 17em; @@ -479,8 +568,17 @@ button.ui-button::-moz-focus-inner { border-right-width: 0; border-left-width: 1px; } -.ui-dialog { + +/* Icons */ +.ui-datepicker .ui-icon { + display: block; + text-indent: -99999px; overflow: hidden; + background-repeat: no-repeat; + left: .5em; + top: .3em; +} +.ui-dialog { position: absolute; top: 0; left: 0; @@ -529,68 +627,47 @@ button.ui-button::-moz-focus-inner { margin: .5em .4em .5em 0; cursor: pointer; } -.ui-dialog .ui-resizable-se { - width: 12px; - height: 12px; - right: -5px; - bottom: -5px; - background-position: 16px 16px; -} -.ui-draggable .ui-dialog-titlebar { - cursor: move; +.ui-dialog .ui-resizable-n { + height: 2px; + top: 0; } -.ui-menu { - list-style: none; - padding: 0; - margin: 0; - display: block; - outline: none; +.ui-dialog .ui-resizable-e { + width: 2px; + right: 0; } -.ui-menu .ui-menu { - position: absolute; +.ui-dialog .ui-resizable-s { + height: 2px; + bottom: 0; } -.ui-menu .ui-menu-item { - position: relative; - margin: 0; - padding: 3px 1em 3px .4em; - cursor: pointer; - min-height: 0; /* support: IE7 */ - /* support: IE10, see #8844 */ - list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"); +.ui-dialog .ui-resizable-w { + width: 2px; + left: 0; } -.ui-menu .ui-menu-divider { - margin: 5px 0; - height: 0; - font-size: 0; - line-height: 0; - border-width: 1px 0 0 0; +.ui-dialog .ui-resizable-se, +.ui-dialog .ui-resizable-sw, +.ui-dialog .ui-resizable-ne, +.ui-dialog .ui-resizable-nw { + width: 7px; + height: 7px; } -.ui-menu .ui-state-focus, -.ui-menu .ui-state-active { - margin: -1px; +.ui-dialog .ui-resizable-se { + right: 0; + bottom: 0; } - -/* icon support */ -.ui-menu-icons { - position: relative; +.ui-dialog .ui-resizable-sw { + left: 0; + bottom: 0; } -.ui-menu-icons .ui-menu-item { - padding-left: 2em; +.ui-dialog .ui-resizable-ne { + right: 0; + top: 0; } - -/* left-aligned */ -.ui-menu .ui-icon { - position: absolute; +.ui-dialog .ui-resizable-nw { + left: 0; top: 0; - bottom: 0; - left: .2em; - margin: auto 0; } - -/* right-aligned */ -.ui-menu .ui-menu-icon { - left: auto; - right: 0; +.ui-draggable .ui-dialog-titlebar { + cursor: move; } .ui-progressbar { height: 2em; @@ -604,7 +681,7 @@ button.ui-button::-moz-focus-inner { .ui-progressbar .ui-progressbar-overlay { background: url("data:image/gif;base64,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"); height: 100%; - filter: alpha(opacity=25); /* support: IE8 */ + -ms-filter: "alpha(opacity=25)"; /* support: IE8 */ opacity: 0.25; } .ui-progressbar-indeterminate .ui-progressbar-value { @@ -620,7 +697,6 @@ button.ui-button::-moz-focus-inner { } .ui-selectmenu-menu .ui-menu { overflow: auto; - /* Support: IE7 */ overflow-x: hidden; padding-bottom: 1px; } @@ -636,28 +712,20 @@ button.ui-button::-moz-focus-inner { .ui-selectmenu-open { display: block; } -.ui-selectmenu-button { - display: inline-block; - overflow: hidden; - position: relative; - text-decoration: none; - cursor: pointer; -} -.ui-selectmenu-button span.ui-icon { - right: 0.5em; - left: auto; - margin-top: -8px; - position: absolute; - top: 50%; -} -.ui-selectmenu-button span.ui-selectmenu-text { - text-align: left; - padding: 0.4em 2.1em 0.4em 1em; +.ui-selectmenu-text { display: block; - line-height: 1.4; + margin-right: 20px; overflow: hidden; text-overflow: ellipsis; +} +.ui-selectmenu-button.ui-button { + text-align: left; white-space: nowrap; + width: 14em; +} +.ui-selectmenu-icon.ui-icon { + float: right; + margin-top: 0; } .ui-slider { position: relative; @@ -668,7 +736,7 @@ button.ui-button::-moz-focus-inner { z-index: 2; width: 1.2em; height: 1.2em; - cursor: default; + cursor: pointer; -ms-touch-action: none; touch-action: none; } @@ -735,14 +803,14 @@ button.ui-button::-moz-focus-inner { border: none; background: none; color: inherit; - padding: 0; + padding: .222em 0; margin: .2em 0; vertical-align: middle; margin-left: .4em; - margin-right: 22px; + margin-right: 2em; } .ui-spinner-button { - width: 16px; + width: 1.6em; height: 50%; font-size: .5em; padding: 0; @@ -756,16 +824,9 @@ button.ui-button::-moz-focus-inner { } /* more specificity required here to override default borders */ .ui-spinner a.ui-spinner-button { - border-top: none; - border-bottom: none; - border-right: none; -} -/* vertically center icon */ -.ui-spinner .ui-icon { - position: absolute; - margin-top: -8px; - top: 50%; - left: 0; + border-top-style: none; + border-bottom-style: none; + border-right-style: none; } .ui-spinner-up { top: 0; @@ -773,12 +834,6 @@ button.ui-button::-moz-focus-inner { .ui-spinner-down { bottom: 0; } - -/* TR overrides */ -.ui-spinner .ui-icon-triangle-1-s { - /* need to fix icons sprite */ - background-position: -65px -16px; -} .ui-tabs { position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ padding: .2em; @@ -825,8 +880,6 @@ button.ui-button::-moz-focus-inner { position: absolute; z-index: 9999; max-width: 300px; - -webkit-box-shadow: 0 0 5px #aaa; - box-shadow: 0 0 5px #aaa; } body .ui-tooltip { border-width: 2px; diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Css/jQueryUI/jquery-ui.theme.css b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Css/jQueryUI/jquery-ui.theme.css index add09e19b7e..c8efe4317c5 100644 --- a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Css/jQueryUI/jquery-ui.theme.css +++ b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Css/jQueryUI/jquery-ui.theme.css @@ -1,5 +1,5 @@ /*! - * jQuery UI CSS Framework 1.11.4 + * jQuery UI CSS Framework 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -8,15 +8,15 @@ * * http://api.jqueryui.com/category/theming/ * - * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px + * To view and modify this theme, visit http://jqueryui.com/themeroller/?scope=&folderName=base&cornerRadiusShadow=8px&offsetLeftShadow=0px&offsetTopShadow=0px&thicknessShadow=5px&opacityShadow=30&bgImgOpacityShadow=0&bgTextureShadow=flat&bgColorShadow=666666&opacityOverlay=30&bgImgOpacityOverlay=0&bgTextureOverlay=flat&bgColorOverlay=aaaaaa&iconColorError=cc0000&fcError=5f3f3f&borderColorError=f1a899&bgTextureError=flat&bgColorError=fddfdf&iconColorHighlight=777620&fcHighlight=777620&borderColorHighlight=dad55e&bgTextureHighlight=flat&bgColorHighlight=fffa90&iconColorActive=ffffff&fcActive=ffffff&borderColorActive=003eff&bgTextureActive=flat&bgColorActive=007fff&iconColorHover=555555&fcHover=2b2b2b&borderColorHover=cccccc&bgTextureHover=flat&bgColorHover=ededed&iconColorDefault=777777&fcDefault=454545&borderColorDefault=c5c5c5&bgTextureDefault=flat&bgColorDefault=f6f6f6&iconColorContent=444444&fcContent=333333&borderColorContent=dddddd&bgTextureContent=flat&bgColorContent=ffffff&iconColorHeader=444444&fcHeader=333333&borderColorHeader=dddddd&bgTextureHeader=flat&bgColorHeader=e9e9e9&cornerRadius=3px&fwDefault=normal&fsDefault=1em&ffDefault=Arial%2CHelvetica%2Csans-serif */ /* Component containers ----------------------------------*/ .ui-widget { - font-family: Verdana,Arial,sans-serif; - font-size: 1.1em; + font-family: Arial,Helvetica,sans-serif; + font-size: 1em; } .ui-widget .ui-widget { font-size: 1em; @@ -25,41 +25,54 @@ .ui-widget select, .ui-widget textarea, .ui-widget button { - font-family: Verdana,Arial,sans-serif; + font-family: Arial,Helvetica,sans-serif; font-size: 1em; } +.ui-widget.ui-widget-content { + border: 1px solid #c5c5c5; +} .ui-widget-content { - border: 1px solid #aaaaaa; + border: 1px solid #dddddd; background: #ffffff; - color: #222222; + color: #333333; } .ui-widget-content a { - color: #222222; + color: #333333; } .ui-widget-header { - border: 1px solid #aaaaaa; - background: #cccccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x; - color: #222222; + border: 1px solid #dddddd; + background: #e9e9e9; + color: #333333; font-weight: bold; } .ui-widget-header a { - color: #222222; + color: #333333; } /* Interaction states ----------------------------------*/ .ui-state-default, .ui-widget-content .ui-state-default, -.ui-widget-header .ui-state-default { - border: 1px solid #d3d3d3; - background: #e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x; +.ui-widget-header .ui-state-default, +.ui-button, + +/* We use html here because we need a greater specificity to make sure disabled +works properly when clicked or hovered */ +html .ui-button.ui-state-disabled:hover, +html .ui-button.ui-state-disabled:active { + border: 1px solid #c5c5c5; + background: #f6f6f6; font-weight: normal; - color: #555555; + color: #454545; } .ui-state-default a, .ui-state-default a:link, -.ui-state-default a:visited { - color: #555555; +.ui-state-default a:visited, +a.ui-button, +a:link.ui-button, +a:visited.ui-button, +.ui-button { + color: #454545; text-decoration: none; } .ui-state-hover, @@ -67,11 +80,13 @@ .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, -.ui-widget-header .ui-state-focus { - border: 1px solid #999999; - background: #dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x; +.ui-widget-header .ui-state-focus, +.ui-button:hover, +.ui-button:focus { + border: 1px solid #cccccc; + background: #ededed; font-weight: normal; - color: #212121; + color: #2b2b2b; } .ui-state-hover a, .ui-state-hover a:hover, @@ -80,22 +95,36 @@ .ui-state-focus a, .ui-state-focus a:hover, .ui-state-focus a:link, -.ui-state-focus a:visited { - color: #212121; +.ui-state-focus a:visited, +a.ui-button:hover, +a.ui-button:focus { + color: #2b2b2b; text-decoration: none; } + +.ui-visual-focus { + box-shadow: 0 0 3px 1px rgb(94, 158, 214); +} .ui-state-active, .ui-widget-content .ui-state-active, -.ui-widget-header .ui-state-active { - border: 1px solid #aaaaaa; - background: #ffffff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x; +.ui-widget-header .ui-state-active, +a.ui-button:active, +.ui-button:active, +.ui-button.ui-state-active:hover { + border: 1px solid #003eff; + background: #007fff; font-weight: normal; - color: #212121; + color: #ffffff; +} +.ui-icon-background, +.ui-state-active .ui-icon-background { + border: #003eff; + background-color: #ffffff; } .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { - color: #212121; + color: #ffffff; text-decoration: none; } @@ -104,31 +133,35 @@ .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight { - border: 1px solid #fcefa1; - background: #fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x; - color: #363636; + border: 1px solid #dad55e; + background: #fffa90; + color: #777620; +} +.ui-state-checked { + border: 1px solid #dad55e; + background: #fffa90; } .ui-state-highlight a, .ui-widget-content .ui-state-highlight a, .ui-widget-header .ui-state-highlight a { - color: #363636; + color: #777620; } .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error { - border: 1px solid #cd0a0a; - background: #fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x; - color: #cd0a0a; + border: 1px solid #f1a899; + background: #fddfdf; + color: #5f3f3f; } .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { - color: #cd0a0a; + color: #5f3f3f; } .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { - color: #cd0a0a; + color: #5f3f3f; } .ui-priority-primary, .ui-widget-content .ui-priority-primary, @@ -139,18 +172,18 @@ .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; - filter:Alpha(Opacity=70); /* support: IE8 */ + -ms-filter: "alpha(opacity=70)"; /* support: IE8 */ font-weight: normal; } .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; - filter:Alpha(Opacity=35); /* support: IE8 */ + -ms-filter: "alpha(opacity=35)"; /* support: IE8 */ background-image: none; } .ui-state-disabled .ui-icon { - filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */ + -ms-filter: "alpha(opacity=35)"; /* support: IE8 - See #6059 */ } /* Icons @@ -163,46 +196,53 @@ } .ui-icon, .ui-widget-content .ui-icon { - background-image: url("images/ui-icons_222222_256x240.png"); + background-image: url("images/ui-icons_444444_256x240.png"); } .ui-widget-header .ui-icon { - background-image: url("images/ui-icons_222222_256x240.png"); -} -.ui-state-default .ui-icon { - background-image: url("images/ui-icons_888888_256x240.png"); + background-image: url("images/ui-icons_444444_256x240.png"); } .ui-state-hover .ui-icon, -.ui-state-focus .ui-icon { - background-image: url("images/ui-icons_454545_256x240.png"); +.ui-state-focus .ui-icon, +.ui-button:hover .ui-icon, +.ui-button:focus .ui-icon { + background-image: url("images/ui-icons_555555_256x240.png"); } -.ui-state-active .ui-icon { - background-image: url("images/ui-icons_454545_256x240.png"); +.ui-state-active .ui-icon, +.ui-button:active .ui-icon { + background-image: url("images/ui-icons_ffffff_256x240.png"); } -.ui-state-highlight .ui-icon { - background-image: url("images/ui-icons_2e83ff_256x240.png"); +.ui-state-highlight .ui-icon, +.ui-button .ui-state-highlight.ui-icon { + background-image: url("images/ui-icons_777620_256x240.png"); } .ui-state-error .ui-icon, .ui-state-error-text .ui-icon { - background-image: url("images/ui-icons_cd0a0a_256x240.png"); + background-image: url("images/ui-icons_cc0000_256x240.png"); +} +.ui-button .ui-icon { + background-image: url("images/ui-icons_777777_256x240.png"); } /* positioning */ -.ui-icon-blank { background-position: 16px 16px; } -.ui-icon-carat-1-n { background-position: 0 0; } -.ui-icon-carat-1-ne { background-position: -16px 0; } -.ui-icon-carat-1-e { background-position: -32px 0; } -.ui-icon-carat-1-se { background-position: -48px 0; } -.ui-icon-carat-1-s { background-position: -64px 0; } -.ui-icon-carat-1-sw { background-position: -80px 0; } -.ui-icon-carat-1-w { background-position: -96px 0; } -.ui-icon-carat-1-nw { background-position: -112px 0; } -.ui-icon-carat-2-n-s { background-position: -128px 0; } -.ui-icon-carat-2-e-w { background-position: -144px 0; } +/* Three classes needed to override `.ui-button:hover .ui-icon` */ +.ui-icon-blank.ui-icon-blank.ui-icon-blank { + background-image: none; +} +.ui-icon-caret-1-n { background-position: 0 0; } +.ui-icon-caret-1-ne { background-position: -16px 0; } +.ui-icon-caret-1-e { background-position: -32px 0; } +.ui-icon-caret-1-se { background-position: -48px 0; } +.ui-icon-caret-1-s { background-position: -65px 0; } +.ui-icon-caret-1-sw { background-position: -80px 0; } +.ui-icon-caret-1-w { background-position: -96px 0; } +.ui-icon-caret-1-nw { background-position: -112px 0; } +.ui-icon-caret-2-n-s { background-position: -128px 0; } +.ui-icon-caret-2-e-w { background-position: -144px 0; } .ui-icon-triangle-1-n { background-position: 0 -16px; } .ui-icon-triangle-1-ne { background-position: -16px -16px; } .ui-icon-triangle-1-e { background-position: -32px -16px; } .ui-icon-triangle-1-se { background-position: -48px -16px; } -.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-s { background-position: -65px -16px; } .ui-icon-triangle-1-sw { background-position: -80px -16px; } .ui-icon-triangle-1-w { background-position: -96px -16px; } .ui-icon-triangle-1-nw { background-position: -112px -16px; } @@ -212,7 +252,7 @@ .ui-icon-arrow-1-ne { background-position: -16px -32px; } .ui-icon-arrow-1-e { background-position: -32px -32px; } .ui-icon-arrow-1-se { background-position: -48px -32px; } -.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-s { background-position: -65px -32px; } .ui-icon-arrow-1-sw { background-position: -80px -32px; } .ui-icon-arrow-1-w { background-position: -96px -32px; } .ui-icon-arrow-1-nw { background-position: -112px -32px; } @@ -224,7 +264,7 @@ .ui-icon-arrowstop-1-e { background-position: -208px -32px; } .ui-icon-arrowstop-1-s { background-position: -224px -32px; } .ui-icon-arrowstop-1-w { background-position: -240px -32px; } -.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-n { background-position: 1px -48px; } .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } .ui-icon-arrowthick-1-e { background-position: -32px -48px; } .ui-icon-arrowthick-1-se { background-position: -48px -48px; } @@ -373,38 +413,34 @@ .ui-corner-top, .ui-corner-left, .ui-corner-tl { - border-top-left-radius: 4px; + border-top-left-radius: 3px; } .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { - border-top-right-radius: 4px; + border-top-right-radius: 3px; } .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { - border-bottom-left-radius: 4px; + border-bottom-left-radius: 3px; } .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { - border-bottom-right-radius: 4px; + border-bottom-right-radius: 3px; } /* Overlays */ .ui-widget-overlay { background: #aaaaaa; opacity: .3; - filter: Alpha(Opacity=30); /* support: IE8 */ + -ms-filter: Alpha(Opacity=30); /* support: IE8 */ } .ui-widget-shadow { - margin: -8px 0 0 -8px; - padding: 8px; - background: #aaaaaa; - opacity: .3; - filter: Alpha(Opacity=30); /* support: IE8 */ - border-radius: 8px; + -webkit-box-shadow: 0px 0px 5px #666666; + box-shadow: 0px 0px 5px #666666; } diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/affix.js b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/affix.js deleted file mode 100644 index 11a3d39a0dc..00000000000 --- a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/affix.js +++ /dev/null @@ -1,162 +0,0 @@ -/* ======================================================================== - * Bootstrap: affix.js v3.3.5 - * http://getbootstrap.com/javascript/#affix - * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // AFFIX CLASS DEFINITION - // ====================== - - var Affix = function (element, options) { - this.options = $.extend({}, Affix.DEFAULTS, options) - - this.$target = $(this.options.target) - .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) - .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) - - this.$element = $(element) - this.affixed = null - this.unpin = null - this.pinnedOffset = null - - this.checkPosition() - } - - Affix.VERSION = '3.3.5' - - Affix.RESET = 'affix affix-top affix-bottom' - - Affix.DEFAULTS = { - offset: 0, - target: window - } - - Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) { - var scrollTop = this.$target.scrollTop() - var position = this.$element.offset() - var targetHeight = this.$target.height() - - if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false - - if (this.affixed == 'bottom') { - if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom' - return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom' - } - - var initializing = this.affixed == null - var colliderTop = initializing ? scrollTop : position.top - var colliderHeight = initializing ? targetHeight : height - - if (offsetTop != null && scrollTop <= offsetTop) return 'top' - if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom' - - return false - } - - Affix.prototype.getPinnedOffset = function () { - if (this.pinnedOffset) return this.pinnedOffset - this.$element.removeClass(Affix.RESET).addClass('affix') - var scrollTop = this.$target.scrollTop() - var position = this.$element.offset() - return (this.pinnedOffset = position.top - scrollTop) - } - - Affix.prototype.checkPositionWithEventLoop = function () { - setTimeout($.proxy(this.checkPosition, this), 1) - } - - Affix.prototype.checkPosition = function () { - if (!this.$element.is(':visible')) return - - var height = this.$element.height() - var offset = this.options.offset - var offsetTop = offset.top - var offsetBottom = offset.bottom - var scrollHeight = Math.max($(document).height(), $(document.body).height()) - - if (typeof offset != 'object') offsetBottom = offsetTop = offset - if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) - if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) - - var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom) - - if (this.affixed != affix) { - if (this.unpin != null) this.$element.css('top', '') - - var affixType = 'affix' + (affix ? '-' + affix : '') - var e = $.Event(affixType + '.bs.affix') - - this.$element.trigger(e) - - if (e.isDefaultPrevented()) return - - this.affixed = affix - this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null - - this.$element - .removeClass(Affix.RESET) - .addClass(affixType) - .trigger(affixType.replace('affix', 'affixed') + '.bs.affix') - } - - if (affix == 'bottom') { - this.$element.offset({ - top: scrollHeight - height - offsetBottom - }) - } - } - - - // AFFIX PLUGIN DEFINITION - // ======================= - - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.affix') - var options = typeof option == 'object' && option - - if (!data) $this.data('bs.affix', (data = new Affix(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - var old = $.fn.affix - - $.fn.affix = Plugin - $.fn.affix.Constructor = Affix - - - // AFFIX NO CONFLICT - // ================= - - $.fn.affix.noConflict = function () { - $.fn.affix = old - return this - } - - - // AFFIX DATA-API - // ============== - - $(window).on('load', function () { - $('[data-spy="affix"]').each(function () { - var $spy = $(this) - var data = $spy.data() - - data.offset = data.offset || {} - - if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom - if (data.offsetTop != null) data.offset.top = data.offsetTop - - Plugin.call($spy, data) - }) - }) - -}(jQuery); diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/alert.js b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/alert.js index a7787cb56b7..64e8e384352 100644 --- a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/alert.js +++ b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/alert.js @@ -1,94 +1,179 @@ -/* ======================================================================== - * Bootstrap: alert.js v3.3.5 - * http://getbootstrap.com/javascript/#alerts - * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.3.1): alert.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; + * -------------------------------------------------------------------------- + */ + +import $ from 'jquery' +import Util from './util' + +/** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + +const NAME = 'alert' +const VERSION = '4.3.1' +const DATA_KEY = 'bs.alert' +const EVENT_KEY = `.${DATA_KEY}` +const DATA_API_KEY = '.data-api' +const JQUERY_NO_CONFLICT = $.fn[NAME] + +const Selector = { + DISMISS : '[data-dismiss="alert"]' +} + +const Event = { + CLOSE : `close${EVENT_KEY}`, + CLOSED : `closed${EVENT_KEY}`, + CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}` +} + +const ClassName = { + ALERT : 'alert', + FADE : 'fade', + SHOW : 'show' +} + +/** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + +class Alert { + constructor(element) { + this._element = element + } - // ALERT CLASS DEFINITION - // ====================== + // Getters - var dismiss = '[data-dismiss="alert"]' - var Alert = function (el) { - $(el).on('click', dismiss, this.close) + static get VERSION() { + return VERSION } - Alert.VERSION = '3.3.5' + // Public - Alert.TRANSITION_DURATION = 150 + close(element) { + let rootElement = this._element + if (element) { + rootElement = this._getRootElement(element) + } - Alert.prototype.close = function (e) { - var $this = $(this) - var selector = $this.attr('data-target') + const customEvent = this._triggerCloseEvent(rootElement) - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + if (customEvent.isDefaultPrevented()) { + return } - var $parent = $(selector) - - if (e) e.preventDefault() + this._removeElement(rootElement) + } - if (!$parent.length) { - $parent = $this.closest('.alert') - } + dispose() { + $.removeData(this._element, DATA_KEY) + this._element = null + } - $parent.trigger(e = $.Event('close.bs.alert')) + // Private - if (e.isDefaultPrevented()) return + _getRootElement(element) { + const selector = Util.getSelectorFromElement(element) + let parent = false - $parent.removeClass('in') + if (selector) { + parent = document.querySelector(selector) + } - function removeElement() { - // detach from parent, fire event then clean up data - $parent.detach().trigger('closed.bs.alert').remove() + if (!parent) { + parent = $(element).closest(`.${ClassName.ALERT}`)[0] } - $.support.transition && $parent.hasClass('fade') ? - $parent - .one('bsTransitionEnd', removeElement) - .emulateTransitionEnd(Alert.TRANSITION_DURATION) : - removeElement() + return parent } + _triggerCloseEvent(element) { + const closeEvent = $.Event(Event.CLOSE) - // ALERT PLUGIN DEFINITION - // ======================= - - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.alert') - - if (!data) $this.data('bs.alert', (data = new Alert(this))) - if (typeof option == 'string') data[option].call($this) - }) + $(element).trigger(closeEvent) + return closeEvent } - var old = $.fn.alert + _removeElement(element) { + $(element).removeClass(ClassName.SHOW) - $.fn.alert = Plugin - $.fn.alert.Constructor = Alert + if (!$(element).hasClass(ClassName.FADE)) { + this._destroyElement(element) + return + } + const transitionDuration = Util.getTransitionDurationFromElement(element) - // ALERT NO CONFLICT - // ================= + $(element) + .one(Util.TRANSITION_END, (event) => this._destroyElement(element, event)) + .emulateTransitionEnd(transitionDuration) + } - $.fn.alert.noConflict = function () { - $.fn.alert = old - return this + _destroyElement(element) { + $(element) + .detach() + .trigger(Event.CLOSED) + .remove() } + // Static - // ALERT DATA-API - // ============== + static _jQueryInterface(config) { + return this.each(function () { + const $element = $(this) + let data = $element.data(DATA_KEY) - $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + if (!data) { + data = new Alert(this) + $element.data(DATA_KEY, data) + } -}(jQuery); + if (config === 'close') { + data[config](this) + } + }) + } + + static _handleDismiss(alertInstance) { + return function (event) { + if (event) { + event.preventDefault() + } + + alertInstance.close(this) + } + } +} + +/** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + +$(document).on( + Event.CLICK_DATA_API, + Selector.DISMISS, + Alert._handleDismiss(new Alert()) +) + +/** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + +$.fn[NAME] = Alert._jQueryInterface +$.fn[NAME].Constructor = Alert +$.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Alert._jQueryInterface +} + +export default Alert diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/button.js b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/button.js index 15d7dca644a..fcf805502a3 100644 --- a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/button.js +++ b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/button.js @@ -1,120 +1,171 @@ -/* ======================================================================== - * Bootstrap: button.js v3.3.5 - * http://getbootstrap.com/javascript/#buttons - * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.3.1): button.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // BUTTON PUBLIC CLASS DEFINITION - // ============================== - - var Button = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, Button.DEFAULTS, options) - this.isLoading = false + * -------------------------------------------------------------------------- + */ + +import $ from 'jquery' + +/** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + +const NAME = 'button' +const VERSION = '4.3.1' +const DATA_KEY = 'bs.button' +const EVENT_KEY = `.${DATA_KEY}` +const DATA_API_KEY = '.data-api' +const JQUERY_NO_CONFLICT = $.fn[NAME] + +const ClassName = { + ACTIVE : 'active', + BUTTON : 'btn', + FOCUS : 'focus' +} + +const Selector = { + DATA_TOGGLE_CARROT : '[data-toggle^="button"]', + DATA_TOGGLE : '[data-toggle="buttons"]', + INPUT : 'input:not([type="hidden"])', + ACTIVE : '.active', + BUTTON : '.btn' +} + +const Event = { + CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}`, + FOCUS_BLUR_DATA_API : `focus${EVENT_KEY}${DATA_API_KEY} ` + + `blur${EVENT_KEY}${DATA_API_KEY}` +} + +/** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + +class Button { + constructor(element) { + this._element = element } - Button.VERSION = '3.3.5' + // Getters - Button.DEFAULTS = { - loadingText: 'loading...' + static get VERSION() { + return VERSION } - Button.prototype.setState = function (state) { - var d = 'disabled' - var $el = this.$element - var val = $el.is('input') ? 'val' : 'html' - var data = $el.data() - - state += 'Text' - - if (data.resetText == null) $el.data('resetText', $el[val]()) - - // push to event loop to allow forms to submit - setTimeout($.proxy(function () { - $el[val](data[state] == null ? this.options[state] : data[state]) - - if (state == 'loadingText') { - this.isLoading = true - $el.addClass(d).attr(d, d) - } else if (this.isLoading) { - this.isLoading = false - $el.removeClass(d).removeAttr(d) + // Public + + toggle() { + let triggerChangeEvent = true + let addAriaPressed = true + const rootElement = $(this._element).closest( + Selector.DATA_TOGGLE + )[0] + + if (rootElement) { + const input = this._element.querySelector(Selector.INPUT) + + if (input) { + if (input.type === 'radio') { + if (input.checked && + this._element.classList.contains(ClassName.ACTIVE)) { + triggerChangeEvent = false + } else { + const activeElement = rootElement.querySelector(Selector.ACTIVE) + + if (activeElement) { + $(activeElement).removeClass(ClassName.ACTIVE) + } + } + } + + if (triggerChangeEvent) { + if (input.hasAttribute('disabled') || + rootElement.hasAttribute('disabled') || + input.classList.contains('disabled') || + rootElement.classList.contains('disabled')) { + return + } + input.checked = !this._element.classList.contains(ClassName.ACTIVE) + $(input).trigger('change') + } + + input.focus() + addAriaPressed = false } - }, this), 0) - } + } - Button.prototype.toggle = function () { - var changed = true - var $parent = this.$element.closest('[data-toggle="buttons"]') - - if ($parent.length) { - var $input = this.$element.find('input') - if ($input.prop('type') == 'radio') { - if ($input.prop('checked')) changed = false - $parent.find('.active').removeClass('active') - this.$element.addClass('active') - } else if ($input.prop('type') == 'checkbox') { - if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false - this.$element.toggleClass('active') - } - $input.prop('checked', this.$element.hasClass('active')) - if (changed) $input.trigger('change') - } else { - this.$element.attr('aria-pressed', !this.$element.hasClass('active')) - this.$element.toggleClass('active') + if (addAriaPressed) { + this._element.setAttribute('aria-pressed', + !this._element.classList.contains(ClassName.ACTIVE)) + } + + if (triggerChangeEvent) { + $(this._element).toggleClass(ClassName.ACTIVE) } } + dispose() { + $.removeData(this._element, DATA_KEY) + this._element = null + } - // BUTTON PLUGIN DEFINITION - // ======================== + // Static - function Plugin(option) { + static _jQueryInterface(config) { return this.each(function () { - var $this = $(this) - var data = $this.data('bs.button') - var options = typeof option == 'object' && option + let data = $(this).data(DATA_KEY) - if (!data) $this.data('bs.button', (data = new Button(this, options))) + if (!data) { + data = new Button(this) + $(this).data(DATA_KEY, data) + } - if (option == 'toggle') data.toggle() - else if (option) data.setState(option) + if (config === 'toggle') { + data[config]() + } }) } +} - var old = $.fn.button - - $.fn.button = Plugin - $.fn.button.Constructor = Button - +/** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ - // BUTTON NO CONFLICT - // ================== +$(document) + .on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE_CARROT, (event) => { + event.preventDefault() - $.fn.button.noConflict = function () { - $.fn.button = old - return this - } - - - // BUTTON DATA-API - // =============== + let button = event.target - $(document) - .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { - var $btn = $(e.target) - if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') - Plugin.call($btn, 'toggle') - if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault() - }) - .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { - $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) - }) + if (!$(button).hasClass(ClassName.BUTTON)) { + button = $(button).closest(Selector.BUTTON) + } -}(jQuery); + Button._jQueryInterface.call($(button), 'toggle') + }) + .on(Event.FOCUS_BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, (event) => { + const button = $(event.target).closest(Selector.BUTTON)[0] + $(button).toggleClass(ClassName.FOCUS, /^focus(in)?$/.test(event.type)) + }) + +/** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + +$.fn[NAME] = Button._jQueryInterface +$.fn[NAME].Constructor = Button +$.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Button._jQueryInterface +} + +export default Button diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/carousel.js b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/carousel.js index 6b2f1c4bac9..36176dd9c02 100644 --- a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/carousel.js +++ b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/carousel.js @@ -1,237 +1,606 @@ -/* ======================================================================== - * Bootstrap: carousel.js v3.3.5 - * http://getbootstrap.com/javascript/#carousel - * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.3.1): carousel.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ + * -------------------------------------------------------------------------- + */ + +import $ from 'jquery' +import Util from './util' + +/** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + +const NAME = 'carousel' +const VERSION = '4.3.1' +const DATA_KEY = 'bs.carousel' +const EVENT_KEY = `.${DATA_KEY}` +const DATA_API_KEY = '.data-api' +const JQUERY_NO_CONFLICT = $.fn[NAME] +const ARROW_LEFT_KEYCODE = 37 // KeyboardEvent.which value for left arrow key +const ARROW_RIGHT_KEYCODE = 39 // KeyboardEvent.which value for right arrow key +const TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch +const SWIPE_THRESHOLD = 40 + +const Default = { + interval : 5000, + keyboard : true, + slide : false, + pause : 'hover', + wrap : true, + touch : true +} + +const DefaultType = { + interval : '(number|boolean)', + keyboard : 'boolean', + slide : '(boolean|string)', + pause : '(string|boolean)', + wrap : 'boolean', + touch : 'boolean' +} + +const Direction = { + NEXT : 'next', + PREV : 'prev', + LEFT : 'left', + RIGHT : 'right' +} + +const Event = { + SLIDE : `slide${EVENT_KEY}`, + SLID : `slid${EVENT_KEY}`, + KEYDOWN : `keydown${EVENT_KEY}`, + MOUSEENTER : `mouseenter${EVENT_KEY}`, + MOUSELEAVE : `mouseleave${EVENT_KEY}`, + TOUCHSTART : `touchstart${EVENT_KEY}`, + TOUCHMOVE : `touchmove${EVENT_KEY}`, + TOUCHEND : `touchend${EVENT_KEY}`, + POINTERDOWN : `pointerdown${EVENT_KEY}`, + POINTERUP : `pointerup${EVENT_KEY}`, + DRAG_START : `dragstart${EVENT_KEY}`, + LOAD_DATA_API : `load${EVENT_KEY}${DATA_API_KEY}`, + CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}` +} + +const ClassName = { + CAROUSEL : 'carousel', + ACTIVE : 'active', + SLIDE : 'slide', + RIGHT : 'carousel-item-right', + LEFT : 'carousel-item-left', + NEXT : 'carousel-item-next', + PREV : 'carousel-item-prev', + ITEM : 'carousel-item', + POINTER_EVENT : 'pointer-event' +} + +const Selector = { + ACTIVE : '.active', + ACTIVE_ITEM : '.active.carousel-item', + ITEM : '.carousel-item', + ITEM_IMG : '.carousel-item img', + NEXT_PREV : '.carousel-item-next, .carousel-item-prev', + INDICATORS : '.carousel-indicators', + DATA_SLIDE : '[data-slide], [data-slide-to]', + DATA_RIDE : '[data-ride="carousel"]' +} + +const PointerType = { + TOUCH : 'touch', + PEN : 'pen' +} + +/** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ +class Carousel { + constructor(element, config) { + this._items = null + this._interval = null + this._activeElement = null + this._isPaused = false + this._isSliding = false + this.touchTimeout = null + this.touchStartX = 0 + this.touchDeltaX = 0 + + this._config = this._getConfig(config) + this._element = element + this._indicatorsElement = this._element.querySelector(Selector.INDICATORS) + this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0 + this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent) + + this._addEventListeners() + } + + // Getters + static get VERSION() { + return VERSION + } -+function ($) { - 'use strict'; + static get Default() { + return Default + } - // CAROUSEL CLASS DEFINITION - // ========================= + // Public - var Carousel = function (element, options) { - this.$element = $(element) - this.$indicators = this.$element.find('.carousel-indicators') - this.options = options - this.paused = null - this.sliding = null - this.interval = null - this.$active = null - this.$items = null + next() { + if (!this._isSliding) { + this._slide(Direction.NEXT) + } + } - this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) + nextWhenVisible() { + // Don't call next when the page isn't visible + // or the carousel or its parent isn't visible + if (!document.hidden && + ($(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden')) { + this.next() + } + } - this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element - .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) - .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) + prev() { + if (!this._isSliding) { + this._slide(Direction.PREV) + } } - Carousel.VERSION = '3.3.5' + pause(event) { + if (!event) { + this._isPaused = true + } - Carousel.TRANSITION_DURATION = 600 + if (this._element.querySelector(Selector.NEXT_PREV)) { + Util.triggerTransitionEnd(this._element) + this.cycle(true) + } - Carousel.DEFAULTS = { - interval: 5000, - pause: 'hover', - wrap: true, - keyboard: true + clearInterval(this._interval) + this._interval = null } - Carousel.prototype.keydown = function (e) { - if (/input|textarea/i.test(e.target.tagName)) return - switch (e.which) { - case 37: this.prev(); break - case 39: this.next(); break - default: return + cycle(event) { + if (!event) { + this._isPaused = false } - e.preventDefault() + if (this._interval) { + clearInterval(this._interval) + this._interval = null + } + + if (this._config.interval && !this._isPaused) { + this._interval = setInterval( + (document.visibilityState ? this.nextWhenVisible : this.next).bind(this), + this._config.interval + ) + } } - Carousel.prototype.cycle = function (e) { - e || (this.paused = false) + to(index) { + this._activeElement = this._element.querySelector(Selector.ACTIVE_ITEM) - this.interval && clearInterval(this.interval) + const activeIndex = this._getItemIndex(this._activeElement) - this.options.interval - && !this.paused - && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + if (index > this._items.length - 1 || index < 0) { + return + } + + if (this._isSliding) { + $(this._element).one(Event.SLID, () => this.to(index)) + return + } - return this + if (activeIndex === index) { + this.pause() + this.cycle() + return + } + + const direction = index > activeIndex + ? Direction.NEXT + : Direction.PREV + + this._slide(direction, this._items[index]) } - Carousel.prototype.getItemIndex = function (item) { - this.$items = item.parent().children('.item') - return this.$items.index(item || this.$active) + dispose() { + $(this._element).off(EVENT_KEY) + $.removeData(this._element, DATA_KEY) + + this._items = null + this._config = null + this._element = null + this._interval = null + this._isPaused = null + this._isSliding = null + this._activeElement = null + this._indicatorsElement = null } - Carousel.prototype.getItemForDirection = function (direction, active) { - var activeIndex = this.getItemIndex(active) - var willWrap = (direction == 'prev' && activeIndex === 0) - || (direction == 'next' && activeIndex == (this.$items.length - 1)) - if (willWrap && !this.options.wrap) return active - var delta = direction == 'prev' ? -1 : 1 - var itemIndex = (activeIndex + delta) % this.$items.length - return this.$items.eq(itemIndex) + // Private + + _getConfig(config) { + config = { + ...Default, + ...config + } + Util.typeCheckConfig(NAME, config, DefaultType) + return config } - Carousel.prototype.to = function (pos) { - var that = this - var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) + _handleSwipe() { + const absDeltax = Math.abs(this.touchDeltaX) - if (pos > (this.$items.length - 1) || pos < 0) return + if (absDeltax <= SWIPE_THRESHOLD) { + return + } + + const direction = absDeltax / this.touchDeltaX - if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" - if (activeIndex == pos) return this.pause().cycle() + // swipe left + if (direction > 0) { + this.prev() + } - return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) + // swipe right + if (direction < 0) { + this.next() + } } - Carousel.prototype.pause = function (e) { - e || (this.paused = true) + _addEventListeners() { + if (this._config.keyboard) { + $(this._element) + .on(Event.KEYDOWN, (event) => this._keydown(event)) + } - if (this.$element.find('.next, .prev').length && $.support.transition) { - this.$element.trigger($.support.transition.end) - this.cycle(true) + if (this._config.pause === 'hover') { + $(this._element) + .on(Event.MOUSEENTER, (event) => this.pause(event)) + .on(Event.MOUSELEAVE, (event) => this.cycle(event)) } - this.interval = clearInterval(this.interval) + if (this._config.touch) { + this._addTouchEventListeners() + } + } + + _addTouchEventListeners() { + if (!this._touchSupported) { + return + } + + const start = (event) => { + if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { + this.touchStartX = event.originalEvent.clientX + } else if (!this._pointerEvent) { + this.touchStartX = event.originalEvent.touches[0].clientX + } + } - return this + const move = (event) => { + // ensure swiping with one touch and not pinching + if (event.originalEvent.touches && event.originalEvent.touches.length > 1) { + this.touchDeltaX = 0 + } else { + this.touchDeltaX = event.originalEvent.touches[0].clientX - this.touchStartX + } + } + + const end = (event) => { + if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { + this.touchDeltaX = event.originalEvent.clientX - this.touchStartX + } + + this._handleSwipe() + if (this._config.pause === 'hover') { + // If it's a touch-enabled device, mouseenter/leave are fired as + // part of the mouse compatibility events on first tap - the carousel + // would stop cycling until user tapped out of it; + // here, we listen for touchend, explicitly pause the carousel + // (as if it's the second time we tap on it, mouseenter compat event + // is NOT fired) and after a timeout (to allow for mouse compatibility + // events to fire) we explicitly restart cycling + + this.pause() + if (this.touchTimeout) { + clearTimeout(this.touchTimeout) + } + this.touchTimeout = setTimeout((event) => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval) + } + } + + $(this._element.querySelectorAll(Selector.ITEM_IMG)).on(Event.DRAG_START, (e) => e.preventDefault()) + if (this._pointerEvent) { + $(this._element).on(Event.POINTERDOWN, (event) => start(event)) + $(this._element).on(Event.POINTERUP, (event) => end(event)) + + this._element.classList.add(ClassName.POINTER_EVENT) + } else { + $(this._element).on(Event.TOUCHSTART, (event) => start(event)) + $(this._element).on(Event.TOUCHMOVE, (event) => move(event)) + $(this._element).on(Event.TOUCHEND, (event) => end(event)) + } } - Carousel.prototype.next = function () { - if (this.sliding) return - return this.slide('next') + _keydown(event) { + if (/input|textarea/i.test(event.target.tagName)) { + return + } + + switch (event.which) { + case ARROW_LEFT_KEYCODE: + event.preventDefault() + this.prev() + break + case ARROW_RIGHT_KEYCODE: + event.preventDefault() + this.next() + break + default: + } } - Carousel.prototype.prev = function () { - if (this.sliding) return - return this.slide('prev') + _getItemIndex(element) { + this._items = element && element.parentNode + ? [].slice.call(element.parentNode.querySelectorAll(Selector.ITEM)) + : [] + return this._items.indexOf(element) } - Carousel.prototype.slide = function (type, next) { - var $active = this.$element.find('.item.active') - var $next = next || this.getItemForDirection(type, $active) - var isCycling = this.interval - var direction = type == 'next' ? 'left' : 'right' - var that = this + _getItemByDirection(direction, activeElement) { + const isNextDirection = direction === Direction.NEXT + const isPrevDirection = direction === Direction.PREV + const activeIndex = this._getItemIndex(activeElement) + const lastItemIndex = this._items.length - 1 + const isGoingToWrap = isPrevDirection && activeIndex === 0 || + isNextDirection && activeIndex === lastItemIndex + + if (isGoingToWrap && !this._config.wrap) { + return activeElement + } + + const delta = direction === Direction.PREV ? -1 : 1 + const itemIndex = (activeIndex + delta) % this._items.length - if ($next.hasClass('active')) return (this.sliding = false) + return itemIndex === -1 + ? this._items[this._items.length - 1] : this._items[itemIndex] + } - var relatedTarget = $next[0] - var slideEvent = $.Event('slide.bs.carousel', { - relatedTarget: relatedTarget, - direction: direction + _triggerSlideEvent(relatedTarget, eventDirectionName) { + const targetIndex = this._getItemIndex(relatedTarget) + const fromIndex = this._getItemIndex(this._element.querySelector(Selector.ACTIVE_ITEM)) + const slideEvent = $.Event(Event.SLIDE, { + relatedTarget, + direction: eventDirectionName, + from: fromIndex, + to: targetIndex }) - this.$element.trigger(slideEvent) - if (slideEvent.isDefaultPrevented()) return - - this.sliding = true - - isCycling && this.pause() - - if (this.$indicators.length) { - this.$indicators.find('.active').removeClass('active') - var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) - $nextIndicator && $nextIndicator.addClass('active') - } - - var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" - if ($.support.transition && this.$element.hasClass('slide')) { - $next.addClass(type) - $next[0].offsetWidth // force reflow - $active.addClass(direction) - $next.addClass(direction) - $active - .one('bsTransitionEnd', function () { - $next.removeClass([type, direction].join(' ')).addClass('active') - $active.removeClass(['active', direction].join(' ')) - that.sliding = false - setTimeout(function () { - that.$element.trigger(slidEvent) - }, 0) - }) - .emulateTransitionEnd(Carousel.TRANSITION_DURATION) + + $(this._element).trigger(slideEvent) + + return slideEvent + } + + _setActiveIndicatorElement(element) { + if (this._indicatorsElement) { + const indicators = [].slice.call(this._indicatorsElement.querySelectorAll(Selector.ACTIVE)) + $(indicators) + .removeClass(ClassName.ACTIVE) + + const nextIndicator = this._indicatorsElement.children[ + this._getItemIndex(element) + ] + + if (nextIndicator) { + $(nextIndicator).addClass(ClassName.ACTIVE) + } + } + } + + _slide(direction, element) { + const activeElement = this._element.querySelector(Selector.ACTIVE_ITEM) + const activeElementIndex = this._getItemIndex(activeElement) + const nextElement = element || activeElement && + this._getItemByDirection(direction, activeElement) + const nextElementIndex = this._getItemIndex(nextElement) + const isCycling = Boolean(this._interval) + + let directionalClassName + let orderClassName + let eventDirectionName + + if (direction === Direction.NEXT) { + directionalClassName = ClassName.LEFT + orderClassName = ClassName.NEXT + eventDirectionName = Direction.LEFT } else { - $active.removeClass('active') - $next.addClass('active') - this.sliding = false - this.$element.trigger(slidEvent) + directionalClassName = ClassName.RIGHT + orderClassName = ClassName.PREV + eventDirectionName = Direction.RIGHT } - isCycling && this.cycle() + if (nextElement && $(nextElement).hasClass(ClassName.ACTIVE)) { + this._isSliding = false + return + } - return this - } + const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName) + if (slideEvent.isDefaultPrevented()) { + return + } + if (!activeElement || !nextElement) { + // Some weirdness is happening, so we bail + return + } - // CAROUSEL PLUGIN DEFINITION - // ========================== + this._isSliding = true - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.carousel') - var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) - var action = typeof option == 'string' ? option : options.slide - - if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) - if (typeof option == 'number') data.to(option) - else if (action) data[action]() - else if (options.interval) data.pause().cycle() + if (isCycling) { + this.pause() + } + + this._setActiveIndicatorElement(nextElement) + + const slidEvent = $.Event(Event.SLID, { + relatedTarget: nextElement, + direction: eventDirectionName, + from: activeElementIndex, + to: nextElementIndex }) - } - var old = $.fn.carousel + if ($(this._element).hasClass(ClassName.SLIDE)) { + $(nextElement).addClass(orderClassName) - $.fn.carousel = Plugin - $.fn.carousel.Constructor = Carousel + Util.reflow(nextElement) + $(activeElement).addClass(directionalClassName) + $(nextElement).addClass(directionalClassName) - // CAROUSEL NO CONFLICT - // ==================== + const nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10) + if (nextElementInterval) { + this._config.defaultInterval = this._config.defaultInterval || this._config.interval + this._config.interval = nextElementInterval + } else { + this._config.interval = this._config.defaultInterval || this._config.interval + } - $.fn.carousel.noConflict = function () { - $.fn.carousel = old - return this - } + const transitionDuration = Util.getTransitionDurationFromElement(activeElement) + $(activeElement) + .one(Util.TRANSITION_END, () => { + $(nextElement) + .removeClass(`${directionalClassName} ${orderClassName}`) + .addClass(ClassName.ACTIVE) - // CAROUSEL DATA-API - // ================= + $(activeElement).removeClass(`${ClassName.ACTIVE} ${orderClassName} ${directionalClassName}`) - var clickHandler = function (e) { - var href - var $this = $(this) - var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 - if (!$target.hasClass('carousel')) return - var options = $.extend({}, $target.data(), $this.data()) - var slideIndex = $this.attr('data-slide-to') - if (slideIndex) options.interval = false + this._isSliding = false - Plugin.call($target, options) + setTimeout(() => $(this._element).trigger(slidEvent), 0) + }) + .emulateTransitionEnd(transitionDuration) + } else { + $(activeElement).removeClass(ClassName.ACTIVE) + $(nextElement).addClass(ClassName.ACTIVE) - if (slideIndex) { - $target.data('bs.carousel').to(slideIndex) + this._isSliding = false + $(this._element).trigger(slidEvent) } - e.preventDefault() + if (isCycling) { + this.cycle() + } } - $(document) - .on('click.bs.carousel.data-api', '[data-slide]', clickHandler) - .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler) + // Static - $(window).on('load', function () { - $('[data-ride="carousel"]').each(function () { - var $carousel = $(this) - Plugin.call($carousel, $carousel.data()) + static _jQueryInterface(config) { + return this.each(function () { + let data = $(this).data(DATA_KEY) + let _config = { + ...Default, + ...$(this).data() + } + + if (typeof config === 'object') { + _config = { + ..._config, + ...config + } + } + + const action = typeof config === 'string' ? config : _config.slide + + if (!data) { + data = new Carousel(this, _config) + $(this).data(DATA_KEY, data) + } + + if (typeof config === 'number') { + data.to(config) + } else if (typeof action === 'string') { + if (typeof data[action] === 'undefined') { + throw new TypeError(`No method named "${action}"`) + } + data[action]() + } else if (_config.interval && _config.ride) { + data.pause() + data.cycle() + } }) - }) + } + + static _dataApiClickHandler(event) { + const selector = Util.getSelectorFromElement(this) + + if (!selector) { + return + } + + const target = $(selector)[0] + + if (!target || !$(target).hasClass(ClassName.CAROUSEL)) { + return + } -}(jQuery); + const config = { + ...$(target).data(), + ...$(this).data() + } + const slideIndex = this.getAttribute('data-slide-to') + + if (slideIndex) { + config.interval = false + } + + Carousel._jQueryInterface.call($(target), config) + + if (slideIndex) { + $(target).data(DATA_KEY).to(slideIndex) + } + + event.preventDefault() + } +} + +/** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + +$(document) + .on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler) + +$(window).on(Event.LOAD_DATA_API, () => { + const carousels = [].slice.call(document.querySelectorAll(Selector.DATA_RIDE)) + for (let i = 0, len = carousels.length; i < len; i++) { + const $carousel = $(carousels[i]) + Carousel._jQueryInterface.call($carousel, $carousel.data()) + } +}) + +/** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + +$.fn[NAME] = Carousel._jQueryInterface +$.fn[NAME].Constructor = Carousel +$.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Carousel._jQueryInterface +} + +export default Carousel diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/collapse.js b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/collapse.js index 329e5354334..10df450d09b 100644 --- a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/collapse.js +++ b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/collapse.js @@ -1,211 +1,402 @@ -/* ======================================================================== - * Bootstrap: collapse.js v3.3.5 - * http://getbootstrap.com/javascript/#collapse - * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.3.1): collapse.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ + * -------------------------------------------------------------------------- + */ + +import $ from 'jquery' +import Util from './util' + +/** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + +const NAME = 'collapse' +const VERSION = '4.3.1' +const DATA_KEY = 'bs.collapse' +const EVENT_KEY = `.${DATA_KEY}` +const DATA_API_KEY = '.data-api' +const JQUERY_NO_CONFLICT = $.fn[NAME] + +const Default = { + toggle : true, + parent : '' +} + +const DefaultType = { + toggle : 'boolean', + parent : '(string|element)' +} + +const Event = { + SHOW : `show${EVENT_KEY}`, + SHOWN : `shown${EVENT_KEY}`, + HIDE : `hide${EVENT_KEY}`, + HIDDEN : `hidden${EVENT_KEY}`, + CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}` +} + +const ClassName = { + SHOW : 'show', + COLLAPSE : 'collapse', + COLLAPSING : 'collapsing', + COLLAPSED : 'collapsed' +} + +const Dimension = { + WIDTH : 'width', + HEIGHT : 'height' +} + +const Selector = { + ACTIVES : '.show, .collapsing', + DATA_TOGGLE : '[data-toggle="collapse"]' +} + +/** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + +class Collapse { + constructor(element, config) { + this._isTransitioning = false + this._element = element + this._config = this._getConfig(config) + this._triggerArray = [].slice.call(document.querySelectorAll( + `[data-toggle="collapse"][href="#${element.id}"],` + + `[data-toggle="collapse"][data-target="#${element.id}"]` + )) + + const toggleList = [].slice.call(document.querySelectorAll(Selector.DATA_TOGGLE)) + for (let i = 0, len = toggleList.length; i < len; i++) { + const elem = toggleList[i] + const selector = Util.getSelectorFromElement(elem) + const filterElement = [].slice.call(document.querySelectorAll(selector)) + .filter((foundElem) => foundElem === element) + + if (selector !== null && filterElement.length > 0) { + this._selector = selector + this._triggerArray.push(elem) + } + } + + this._parent = this._config.parent ? this._getParent() : null + if (!this._config.parent) { + this._addAriaAndCollapsedClass(this._element, this._triggerArray) + } -+function ($) { - 'use strict'; + if (this._config.toggle) { + this.toggle() + } + } - // COLLAPSE PUBLIC CLASS DEFINITION - // ================================ + // Getters - var Collapse = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, Collapse.DEFAULTS, options) - this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' + - '[data-toggle="collapse"][data-target="#' + element.id + '"]') - this.transitioning = null + static get VERSION() { + return VERSION + } - if (this.options.parent) { - this.$parent = this.getParent() + static get Default() { + return Default + } + + // Public + + toggle() { + if ($(this._element).hasClass(ClassName.SHOW)) { + this.hide() } else { - this.addAriaAndCollapsedClass(this.$element, this.$trigger) + this.show() } - - if (this.options.toggle) this.toggle() } - Collapse.VERSION = '3.3.5' + show() { + if (this._isTransitioning || + $(this._element).hasClass(ClassName.SHOW)) { + return + } - Collapse.TRANSITION_DURATION = 350 + let actives + let activesData - Collapse.DEFAULTS = { - toggle: true - } + if (this._parent) { + actives = [].slice.call(this._parent.querySelectorAll(Selector.ACTIVES)) + .filter((elem) => { + if (typeof this._config.parent === 'string') { + return elem.getAttribute('data-parent') === this._config.parent + } - Collapse.prototype.dimension = function () { - var hasWidth = this.$element.hasClass('width') - return hasWidth ? 'width' : 'height' - } + return elem.classList.contains(ClassName.COLLAPSE) + }) - Collapse.prototype.show = function () { - if (this.transitioning || this.$element.hasClass('in')) return + if (actives.length === 0) { + actives = null + } + } + + if (actives) { + activesData = $(actives).not(this._selector).data(DATA_KEY) + if (activesData && activesData._isTransitioning) { + return + } + } - var activesData - var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing') + const startEvent = $.Event(Event.SHOW) + $(this._element).trigger(startEvent) + if (startEvent.isDefaultPrevented()) { + return + } - if (actives && actives.length) { - activesData = actives.data('bs.collapse') - if (activesData && activesData.transitioning) return + if (actives) { + Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide') + if (!activesData) { + $(actives).data(DATA_KEY, null) + } } - var startEvent = $.Event('show.bs.collapse') - this.$element.trigger(startEvent) - if (startEvent.isDefaultPrevented()) return + const dimension = this._getDimension() + + $(this._element) + .removeClass(ClassName.COLLAPSE) + .addClass(ClassName.COLLAPSING) + + this._element.style[dimension] = 0 - if (actives && actives.length) { - Plugin.call(actives, 'hide') - activesData || actives.data('bs.collapse', null) + if (this._triggerArray.length) { + $(this._triggerArray) + .removeClass(ClassName.COLLAPSED) + .attr('aria-expanded', true) } - var dimension = this.dimension() + this.setTransitioning(true) - this.$element - .removeClass('collapse') - .addClass('collapsing')[dimension](0) - .attr('aria-expanded', true) + const complete = () => { + $(this._element) + .removeClass(ClassName.COLLAPSING) + .addClass(ClassName.COLLAPSE) + .addClass(ClassName.SHOW) - this.$trigger - .removeClass('collapsed') - .attr('aria-expanded', true) + this._element.style[dimension] = '' - this.transitioning = 1 + this.setTransitioning(false) - var complete = function () { - this.$element - .removeClass('collapsing') - .addClass('collapse in')[dimension]('') - this.transitioning = 0 - this.$element - .trigger('shown.bs.collapse') + $(this._element).trigger(Event.SHOWN) } - if (!$.support.transition) return complete.call(this) + const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1) + const scrollSize = `scroll${capitalizedDimension}` + const transitionDuration = Util.getTransitionDurationFromElement(this._element) - var scrollSize = $.camelCase(['scroll', dimension].join('-')) + $(this._element) + .one(Util.TRANSITION_END, complete) + .emulateTransitionEnd(transitionDuration) - this.$element - .one('bsTransitionEnd', $.proxy(complete, this)) - .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) + this._element.style[dimension] = `${this._element[scrollSize]}px` } - Collapse.prototype.hide = function () { - if (this.transitioning || !this.$element.hasClass('in')) return + hide() { + if (this._isTransitioning || + !$(this._element).hasClass(ClassName.SHOW)) { + return + } - var startEvent = $.Event('hide.bs.collapse') - this.$element.trigger(startEvent) - if (startEvent.isDefaultPrevented()) return + const startEvent = $.Event(Event.HIDE) + $(this._element).trigger(startEvent) + if (startEvent.isDefaultPrevented()) { + return + } - var dimension = this.dimension() + const dimension = this._getDimension() - this.$element[dimension](this.$element[dimension]())[0].offsetHeight + this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px` - this.$element - .addClass('collapsing') - .removeClass('collapse in') - .attr('aria-expanded', false) + Util.reflow(this._element) - this.$trigger - .addClass('collapsed') - .attr('aria-expanded', false) + $(this._element) + .addClass(ClassName.COLLAPSING) + .removeClass(ClassName.COLLAPSE) + .removeClass(ClassName.SHOW) - this.transitioning = 1 + const triggerArrayLength = this._triggerArray.length + if (triggerArrayLength > 0) { + for (let i = 0; i < triggerArrayLength; i++) { + const trigger = this._triggerArray[i] + const selector = Util.getSelectorFromElement(trigger) - var complete = function () { - this.transitioning = 0 - this.$element - .removeClass('collapsing') - .addClass('collapse') - .trigger('hidden.bs.collapse') + if (selector !== null) { + const $elem = $([].slice.call(document.querySelectorAll(selector))) + if (!$elem.hasClass(ClassName.SHOW)) { + $(trigger).addClass(ClassName.COLLAPSED) + .attr('aria-expanded', false) + } + } + } } - if (!$.support.transition) return complete.call(this) + this.setTransitioning(true) - this.$element - [dimension](0) - .one('bsTransitionEnd', $.proxy(complete, this)) - .emulateTransitionEnd(Collapse.TRANSITION_DURATION) - } + const complete = () => { + this.setTransitioning(false) + $(this._element) + .removeClass(ClassName.COLLAPSING) + .addClass(ClassName.COLLAPSE) + .trigger(Event.HIDDEN) + } + + this._element.style[dimension] = '' + const transitionDuration = Util.getTransitionDurationFromElement(this._element) - Collapse.prototype.toggle = function () { - this[this.$element.hasClass('in') ? 'hide' : 'show']() + $(this._element) + .one(Util.TRANSITION_END, complete) + .emulateTransitionEnd(transitionDuration) } - Collapse.prototype.getParent = function () { - return $(this.options.parent) - .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') - .each($.proxy(function (i, element) { - var $element = $(element) - this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) - }, this)) - .end() + setTransitioning(isTransitioning) { + this._isTransitioning = isTransitioning } - Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { - var isOpen = $element.hasClass('in') + dispose() { + $.removeData(this._element, DATA_KEY) - $element.attr('aria-expanded', isOpen) - $trigger - .toggleClass('collapsed', !isOpen) - .attr('aria-expanded', isOpen) + this._config = null + this._parent = null + this._element = null + this._triggerArray = null + this._isTransitioning = null } - function getTargetFromTrigger($trigger) { - var href - var target = $trigger.attr('data-target') - || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 + // Private - return $(target) + _getConfig(config) { + config = { + ...Default, + ...config + } + config.toggle = Boolean(config.toggle) // Coerce string values + Util.typeCheckConfig(NAME, config, DefaultType) + return config } + _getDimension() { + const hasWidth = $(this._element).hasClass(Dimension.WIDTH) + return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT + } - // COLLAPSE PLUGIN DEFINITION - // ========================== + _getParent() { + let parent - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.collapse') - var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + if (Util.isElement(this._config.parent)) { + parent = this._config.parent - if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false - if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) - if (typeof option == 'string') data[option]() - }) - } + // It's a jQuery object + if (typeof this._config.parent.jquery !== 'undefined') { + parent = this._config.parent[0] + } + } else { + parent = document.querySelector(this._config.parent) + } - var old = $.fn.collapse + const selector = + `[data-toggle="collapse"][data-parent="${this._config.parent}"]` - $.fn.collapse = Plugin - $.fn.collapse.Constructor = Collapse + const children = [].slice.call(parent.querySelectorAll(selector)) + $(children).each((i, element) => { + this._addAriaAndCollapsedClass( + Collapse._getTargetFromElement(element), + [element] + ) + }) + return parent + } - // COLLAPSE NO CONFLICT - // ==================== + _addAriaAndCollapsedClass(element, triggerArray) { + const isOpen = $(element).hasClass(ClassName.SHOW) - $.fn.collapse.noConflict = function () { - $.fn.collapse = old - return this + if (triggerArray.length) { + $(triggerArray) + .toggleClass(ClassName.COLLAPSED, !isOpen) + .attr('aria-expanded', isOpen) + } } + // Static - // COLLAPSE DATA-API - // ================= - - $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { - var $this = $(this) + static _getTargetFromElement(element) { + const selector = Util.getSelectorFromElement(element) + return selector ? document.querySelector(selector) : null + } - if (!$this.attr('data-target')) e.preventDefault() + static _jQueryInterface(config) { + return this.each(function () { + const $this = $(this) + let data = $this.data(DATA_KEY) + const _config = { + ...Default, + ...$this.data(), + ...typeof config === 'object' && config ? config : {} + } + + if (!data && _config.toggle && /show|hide/.test(config)) { + _config.toggle = false + } + + if (!data) { + data = new Collapse(this, _config) + $this.data(DATA_KEY, data) + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`) + } + data[config]() + } + }) + } +} + +/** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + +$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { + // preventDefault only for elements (which change the URL) not inside the collapsible element + if (event.currentTarget.tagName === 'A') { + event.preventDefault() + } - var $target = getTargetFromTrigger($this) - var data = $target.data('bs.collapse') - var option = data ? 'toggle' : $this.data() + const $trigger = $(this) + const selector = Util.getSelectorFromElement(this) + const selectors = [].slice.call(document.querySelectorAll(selector)) - Plugin.call($target, option) + $(selectors).each(function () { + const $target = $(this) + const data = $target.data(DATA_KEY) + const config = data ? 'toggle' : $trigger.data() + Collapse._jQueryInterface.call($target, config) }) - -}(jQuery); +}) + +/** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + +$.fn[NAME] = Collapse._jQueryInterface +$.fn[NAME].Constructor = Collapse +$.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Collapse._jQueryInterface +} + +export default Collapse diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/dropdown.js b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/dropdown.js index bc4d3734343..d336a46d917 100644 --- a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/dropdown.js +++ b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/dropdown.js @@ -1,165 +1,545 @@ -/* ======================================================================== - * Bootstrap: dropdown.js v3.3.5 - * http://getbootstrap.com/javascript/#dropdowns - * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.3.1): dropdown.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ + * -------------------------------------------------------------------------- + */ + +import $ from 'jquery' +import Popper from 'popper.js' +import Util from './util' + +/** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + +const NAME = 'dropdown' +const VERSION = '4.3.1' +const DATA_KEY = 'bs.dropdown' +const EVENT_KEY = `.${DATA_KEY}` +const DATA_API_KEY = '.data-api' +const JQUERY_NO_CONFLICT = $.fn[NAME] +const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key +const SPACE_KEYCODE = 32 // KeyboardEvent.which value for space key +const TAB_KEYCODE = 9 // KeyboardEvent.which value for tab key +const ARROW_UP_KEYCODE = 38 // KeyboardEvent.which value for up arrow key +const ARROW_DOWN_KEYCODE = 40 // KeyboardEvent.which value for down arrow key +const RIGHT_MOUSE_BUTTON_WHICH = 3 // MouseEvent.which value for the right button (assuming a right-handed mouse) +const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEYCODE}|${ARROW_DOWN_KEYCODE}|${ESCAPE_KEYCODE}`) + +const Event = { + HIDE : `hide${EVENT_KEY}`, + HIDDEN : `hidden${EVENT_KEY}`, + SHOW : `show${EVENT_KEY}`, + SHOWN : `shown${EVENT_KEY}`, + CLICK : `click${EVENT_KEY}`, + CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}`, + KEYDOWN_DATA_API : `keydown${EVENT_KEY}${DATA_API_KEY}`, + KEYUP_DATA_API : `keyup${EVENT_KEY}${DATA_API_KEY}` +} + +const ClassName = { + DISABLED : 'disabled', + SHOW : 'show', + DROPUP : 'dropup', + DROPRIGHT : 'dropright', + DROPLEFT : 'dropleft', + MENURIGHT : 'dropdown-menu-right', + MENULEFT : 'dropdown-menu-left', + POSITION_STATIC : 'position-static' +} + +const Selector = { + DATA_TOGGLE : '[data-toggle="dropdown"]', + FORM_CHILD : '.dropdown form', + MENU : '.dropdown-menu', + NAVBAR_NAV : '.navbar-nav', + VISIBLE_ITEMS : '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)' +} + +const AttachmentMap = { + TOP : 'top-start', + TOPEND : 'top-end', + BOTTOM : 'bottom-start', + BOTTOMEND : 'bottom-end', + RIGHT : 'right-start', + RIGHTEND : 'right-end', + LEFT : 'left-start', + LEFTEND : 'left-end' +} + +const Default = { + offset : 0, + flip : true, + boundary : 'scrollParent', + reference : 'toggle', + display : 'dynamic' +} + +const DefaultType = { + offset : '(number|string|function)', + flip : 'boolean', + boundary : '(string|element)', + reference : '(string|element)', + display : 'string' +} + +/** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + +class Dropdown { + constructor(element, config) { + this._element = element + this._popper = null + this._config = this._getConfig(config) + this._menu = this._getMenuElement() + this._inNavbar = this._detectNavbar() + + this._addEventListeners() + } + // Getters -+function ($) { - 'use strict'; + static get VERSION() { + return VERSION + } - // DROPDOWN CLASS DEFINITION - // ========================= + static get Default() { + return Default + } - var backdrop = '.dropdown-backdrop' - var toggle = '[data-toggle="dropdown"]' - var Dropdown = function (element) { - $(element).on('click.bs.dropdown', this.toggle) + static get DefaultType() { + return DefaultType } - Dropdown.VERSION = '3.3.5' + // Public - function getParent($this) { - var selector = $this.attr('data-target') + toggle() { + if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED)) { + return + } - if (!selector) { - selector = $this.attr('href') - selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + const parent = Dropdown._getParentFromElement(this._element) + const isActive = $(this._menu).hasClass(ClassName.SHOW) + + Dropdown._clearMenus() + + if (isActive) { + return } - var $parent = selector && $(selector) + const relatedTarget = { + relatedTarget: this._element + } + const showEvent = $.Event(Event.SHOW, relatedTarget) - return $parent && $parent.length ? $parent : $this.parent() - } + $(parent).trigger(showEvent) - function clearMenus(e) { - if (e && e.which === 3) return - $(backdrop).remove() - $(toggle).each(function () { - var $this = $(this) - var $parent = getParent($this) - var relatedTarget = { relatedTarget: this } + if (showEvent.isDefaultPrevented()) { + return + } - if (!$parent.hasClass('open')) return + // Disable totally Popper.js for Dropdown in Navbar + if (!this._inNavbar) { + /** + * Check for Popper dependency + * Popper - https://popper.js.org + */ + if (typeof Popper === 'undefined') { + throw new TypeError('Bootstrap\'s dropdowns require Popper.js (https://popper.js.org/)') + } - if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return + let referenceElement = this._element - $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget)) + if (this._config.reference === 'parent') { + referenceElement = parent + } else if (Util.isElement(this._config.reference)) { + referenceElement = this._config.reference - if (e.isDefaultPrevented()) return + // Check if it's jQuery element + if (typeof this._config.reference.jquery !== 'undefined') { + referenceElement = this._config.reference[0] + } + } - $this.attr('aria-expanded', 'false') - $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget) - }) + // If boundary is not `scrollParent`, then set position to `static` + // to allow the menu to "escape" the scroll parent's boundaries + // https://github.com/twbs/bootstrap/issues/24251 + if (this._config.boundary !== 'scrollParent') { + $(parent).addClass(ClassName.POSITION_STATIC) + } + this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig()) + } + + // If this is a touch-enabled device we add extra + // empty mouseover listeners to the body's immediate children; + // only needed because of broken event delegation on iOS + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + if ('ontouchstart' in document.documentElement && + $(parent).closest(Selector.NAVBAR_NAV).length === 0) { + $(document.body).children().on('mouseover', null, $.noop) + } + + this._element.focus() + this._element.setAttribute('aria-expanded', true) + + $(this._menu).toggleClass(ClassName.SHOW) + $(parent) + .toggleClass(ClassName.SHOW) + .trigger($.Event(Event.SHOWN, relatedTarget)) } - Dropdown.prototype.toggle = function (e) { - var $this = $(this) + show() { + if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED) || $(this._menu).hasClass(ClassName.SHOW)) { + return + } + + const relatedTarget = { + relatedTarget: this._element + } + const showEvent = $.Event(Event.SHOW, relatedTarget) + const parent = Dropdown._getParentFromElement(this._element) - if ($this.is('.disabled, :disabled')) return + $(parent).trigger(showEvent) - var $parent = getParent($this) - var isActive = $parent.hasClass('open') + if (showEvent.isDefaultPrevented()) { + return + } - clearMenus() + $(this._menu).toggleClass(ClassName.SHOW) + $(parent) + .toggleClass(ClassName.SHOW) + .trigger($.Event(Event.SHOWN, relatedTarget)) + } - if (!isActive) { - if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { - // if mobile we use a backdrop because click events don't delegate - $(document.createElement('div')) - .addClass('dropdown-backdrop') - .insertAfter($(this)) - .on('click', clearMenus) - } + hide() { + if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED) || !$(this._menu).hasClass(ClassName.SHOW)) { + return + } - var relatedTarget = { relatedTarget: this } - $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget)) + const relatedTarget = { + relatedTarget: this._element + } + const hideEvent = $.Event(Event.HIDE, relatedTarget) + const parent = Dropdown._getParentFromElement(this._element) + + $(parent).trigger(hideEvent) - if (e.isDefaultPrevented()) return + if (hideEvent.isDefaultPrevented()) { + return + } - $this - .trigger('focus') - .attr('aria-expanded', 'true') + $(this._menu).toggleClass(ClassName.SHOW) + $(parent) + .toggleClass(ClassName.SHOW) + .trigger($.Event(Event.HIDDEN, relatedTarget)) + } - $parent - .toggleClass('open') - .trigger('shown.bs.dropdown', relatedTarget) + dispose() { + $.removeData(this._element, DATA_KEY) + $(this._element).off(EVENT_KEY) + this._element = null + this._menu = null + if (this._popper !== null) { + this._popper.destroy() + this._popper = null } + } - return false + update() { + this._inNavbar = this._detectNavbar() + if (this._popper !== null) { + this._popper.scheduleUpdate() + } } - Dropdown.prototype.keydown = function (e) { - if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return + // Private - var $this = $(this) + _addEventListeners() { + $(this._element).on(Event.CLICK, (event) => { + event.preventDefault() + event.stopPropagation() + this.toggle() + }) + } - e.preventDefault() - e.stopPropagation() + _getConfig(config) { + config = { + ...this.constructor.Default, + ...$(this._element).data(), + ...config + } - if ($this.is('.disabled, :disabled')) return + Util.typeCheckConfig( + NAME, + config, + this.constructor.DefaultType + ) - var $parent = getParent($this) - var isActive = $parent.hasClass('open') + return config + } + + _getMenuElement() { + if (!this._menu) { + const parent = Dropdown._getParentFromElement(this._element) - if (!isActive && e.which != 27 || isActive && e.which == 27) { - if (e.which == 27) $parent.find(toggle).trigger('focus') - return $this.trigger('click') + if (parent) { + this._menu = parent.querySelector(Selector.MENU) + } } + return this._menu + } + + _getPlacement() { + const $parentDropdown = $(this._element.parentNode) + let placement = AttachmentMap.BOTTOM + + // Handle dropup + if ($parentDropdown.hasClass(ClassName.DROPUP)) { + placement = AttachmentMap.TOP + if ($(this._menu).hasClass(ClassName.MENURIGHT)) { + placement = AttachmentMap.TOPEND + } + } else if ($parentDropdown.hasClass(ClassName.DROPRIGHT)) { + placement = AttachmentMap.RIGHT + } else if ($parentDropdown.hasClass(ClassName.DROPLEFT)) { + placement = AttachmentMap.LEFT + } else if ($(this._menu).hasClass(ClassName.MENURIGHT)) { + placement = AttachmentMap.BOTTOMEND + } + return placement + } - var desc = ' li:not(.disabled):visible a' - var $items = $parent.find('.dropdown-menu' + desc) + _detectNavbar() { + return $(this._element).closest('.navbar').length > 0 + } - if (!$items.length) return + _getOffset() { + const offset = {} - var index = $items.index(e.target) + if (typeof this._config.offset === 'function') { + offset.fn = (data) => { + data.offsets = { + ...data.offsets, + ...this._config.offset(data.offsets, this._element) || {} + } - if (e.which == 38 && index > 0) index-- // up - if (e.which == 40 && index < $items.length - 1) index++ // down - if (!~index) index = 0 + return data + } + } else { + offset.offset = this._config.offset + } - $items.eq(index).trigger('focus') + return offset } + _getPopperConfig() { + const popperConfig = { + placement: this._getPlacement(), + modifiers: { + offset: this._getOffset(), + flip: { + enabled: this._config.flip + }, + preventOverflow: { + boundariesElement: this._config.boundary + } + } + } + + // Disable Popper.js if we have a static display + if (this._config.display === 'static') { + popperConfig.modifiers.applyStyle = { + enabled: false + } + } + + return popperConfig + } - // DROPDOWN PLUGIN DEFINITION - // ========================== + // Static - function Plugin(option) { + static _jQueryInterface(config) { return this.each(function () { - var $this = $(this) - var data = $this.data('bs.dropdown') + let data = $(this).data(DATA_KEY) + const _config = typeof config === 'object' ? config : null - if (!data) $this.data('bs.dropdown', (data = new Dropdown(this))) - if (typeof option == 'string') data[option].call($this) + if (!data) { + data = new Dropdown(this, _config) + $(this).data(DATA_KEY, data) + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`) + } + data[config]() + } }) } - var old = $.fn.dropdown + static _clearMenus(event) { + if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || + event.type === 'keyup' && event.which !== TAB_KEYCODE)) { + return + } + + const toggles = [].slice.call(document.querySelectorAll(Selector.DATA_TOGGLE)) + + for (let i = 0, len = toggles.length; i < len; i++) { + const parent = Dropdown._getParentFromElement(toggles[i]) + const context = $(toggles[i]).data(DATA_KEY) + const relatedTarget = { + relatedTarget: toggles[i] + } + + if (event && event.type === 'click') { + relatedTarget.clickEvent = event + } + + if (!context) { + continue + } + + const dropdownMenu = context._menu + if (!$(parent).hasClass(ClassName.SHOW)) { + continue + } + + if (event && (event.type === 'click' && + /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && + $.contains(parent, event.target)) { + continue + } + + const hideEvent = $.Event(Event.HIDE, relatedTarget) + $(parent).trigger(hideEvent) + if (hideEvent.isDefaultPrevented()) { + continue + } + + // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + if ('ontouchstart' in document.documentElement) { + $(document.body).children().off('mouseover', null, $.noop) + } + + toggles[i].setAttribute('aria-expanded', 'false') + + $(dropdownMenu).removeClass(ClassName.SHOW) + $(parent) + .removeClass(ClassName.SHOW) + .trigger($.Event(Event.HIDDEN, relatedTarget)) + } + } + + static _getParentFromElement(element) { + let parent + const selector = Util.getSelectorFromElement(element) - $.fn.dropdown = Plugin - $.fn.dropdown.Constructor = Dropdown + if (selector) { + parent = document.querySelector(selector) + } + return parent || element.parentNode + } + + // eslint-disable-next-line complexity + static _dataApiKeydownHandler(event) { + // If not input/textarea: + // - And not a key in REGEXP_KEYDOWN => not a dropdown command + // If input/textarea: + // - If space key => not a dropdown command + // - If key is other than escape + // - If key is not up or down => not a dropdown command + // - If trigger inside the menu => not a dropdown command + 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.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) { + return + } - // DROPDOWN NO CONFLICT - // ==================== + event.preventDefault() + event.stopPropagation() - $.fn.dropdown.noConflict = function () { - $.fn.dropdown = old - return this + if (this.disabled || $(this).hasClass(ClassName.DISABLED)) { + return + } + + const parent = Dropdown._getParentFromElement(this) + const isActive = $(parent).hasClass(ClassName.SHOW) + + if (!isActive || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) { + if (event.which === ESCAPE_KEYCODE) { + const toggle = parent.querySelector(Selector.DATA_TOGGLE) + $(toggle).trigger('focus') + } + + $(this).trigger('click') + return + } + + const items = [].slice.call(parent.querySelectorAll(Selector.VISIBLE_ITEMS)) + + if (items.length === 0) { + return + } + + let index = items.indexOf(event.target) + + if (event.which === ARROW_UP_KEYCODE && index > 0) { // Up + index-- + } + + if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) { // Down + index++ + } + + if (index < 0) { + index = 0 + } + + items[index].focus() } +} + +/** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + +$(document) + .on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler) + .on(Event.KEYDOWN_DATA_API, Selector.MENU, Dropdown._dataApiKeydownHandler) + .on(`${Event.CLICK_DATA_API} ${Event.KEYUP_DATA_API}`, Dropdown._clearMenus) + .on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { + event.preventDefault() + event.stopPropagation() + Dropdown._jQueryInterface.call($(this), 'toggle') + }) + .on(Event.CLICK_DATA_API, Selector.FORM_CHILD, (e) => { + e.stopPropagation() + }) +/** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ - // APPLY TO STANDARD DROPDOWN ELEMENTS - // =================================== +$.fn[NAME] = Dropdown._jQueryInterface +$.fn[NAME].Constructor = Dropdown +$.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Dropdown._jQueryInterface +} - $(document) - .on('click.bs.dropdown.data-api', clearMenus) - .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) - .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle) - .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown) - .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown) -}(jQuery); +export default Dropdown diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/index.js b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/index.js new file mode 100644 index 00000000000..c4a4d4b1f4d --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/index.js @@ -0,0 +1,52 @@ +import $ from 'jquery' +import Alert from './alert' +import Button from './button' +import Carousel from './carousel' +import Collapse from './collapse' +import Dropdown from './dropdown' +import Modal from './modal' +import Popover from './popover' +import Scrollspy from './scrollspy' +import Tab from './tab' +import Toast from './toast' +import Tooltip from './tooltip' +import Util from './util' + +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.3.1): index.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + +(() => { + if (typeof $ === 'undefined') { + throw new TypeError('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.') + } + + const version = $.fn.jquery.split(' ')[0].split('.') + const minMajor = 1 + const ltMajor = 2 + const minMinor = 9 + const minPatch = 1 + const maxMajor = 4 + + if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) { + throw new Error('Bootstrap\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0') + } +})() + +export { + Util, + Alert, + Button, + Carousel, + Collapse, + Dropdown, + Modal, + Popover, + Scrollspy, + Tab, + Toast, + Tooltip +} diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/modal.js b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/modal.js index d50a856089c..99fe1bf2d08 100644 --- a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/modal.js +++ b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/modal.js @@ -1,337 +1,594 @@ -/* ======================================================================== - * Bootstrap: modal.js v3.3.5 - * http://getbootstrap.com/javascript/#modals - * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.3.1): modal.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // MODAL CLASS DEFINITION - // ====================== - - var Modal = function (element, options) { - this.options = options - this.$body = $(document.body) - this.$element = $(element) - this.$dialog = this.$element.find('.modal-dialog') - this.$backdrop = null - this.isShown = null - this.originalBodyPad = null - this.scrollbarWidth = 0 - this.ignoreBackdropClick = false - - if (this.options.remote) { - this.$element - .find('.modal-content') - .load(this.options.remote, $.proxy(function () { - this.$element.trigger('loaded.bs.modal') - }, this)) - } + * -------------------------------------------------------------------------- + */ + +import $ from 'jquery' +import Util from './util' + +/** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + +const NAME = 'modal' +const VERSION = '4.3.1' +const DATA_KEY = 'bs.modal' +const EVENT_KEY = `.${DATA_KEY}` +const DATA_API_KEY = '.data-api' +const JQUERY_NO_CONFLICT = $.fn[NAME] +const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key + +const Default = { + backdrop : true, + keyboard : true, + focus : true, + show : true +} + +const DefaultType = { + backdrop : '(boolean|string)', + keyboard : 'boolean', + focus : 'boolean', + show : 'boolean' +} + +const Event = { + HIDE : `hide${EVENT_KEY}`, + HIDDEN : `hidden${EVENT_KEY}`, + SHOW : `show${EVENT_KEY}`, + SHOWN : `shown${EVENT_KEY}`, + FOCUSIN : `focusin${EVENT_KEY}`, + RESIZE : `resize${EVENT_KEY}`, + CLICK_DISMISS : `click.dismiss${EVENT_KEY}`, + KEYDOWN_DISMISS : `keydown.dismiss${EVENT_KEY}`, + MOUSEUP_DISMISS : `mouseup.dismiss${EVENT_KEY}`, + MOUSEDOWN_DISMISS : `mousedown.dismiss${EVENT_KEY}`, + CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}` +} + +const ClassName = { + SCROLLABLE : 'modal-dialog-scrollable', + SCROLLBAR_MEASURER : 'modal-scrollbar-measure', + BACKDROP : 'modal-backdrop', + OPEN : 'modal-open', + FADE : 'fade', + SHOW : 'show' +} + +const Selector = { + DIALOG : '.modal-dialog', + MODAL_BODY : '.modal-body', + DATA_TOGGLE : '[data-toggle="modal"]', + DATA_DISMISS : '[data-dismiss="modal"]', + FIXED_CONTENT : '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top', + STICKY_CONTENT : '.sticky-top' +} + +/** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + +class Modal { + constructor(element, config) { + this._config = this._getConfig(config) + this._element = element + this._dialog = element.querySelector(Selector.DIALOG) + this._backdrop = null + this._isShown = false + this._isBodyOverflowing = false + this._ignoreBackdropClick = false + this._isTransitioning = false + this._scrollbarWidth = 0 } - Modal.VERSION = '3.3.5' + // Getters - Modal.TRANSITION_DURATION = 300 - Modal.BACKDROP_TRANSITION_DURATION = 150 + static get VERSION() { + return VERSION + } - Modal.DEFAULTS = { - backdrop: true, - keyboard: true, - show: true + static get Default() { + return Default } - Modal.prototype.toggle = function (_relatedTarget) { - return this.isShown ? this.hide() : this.show(_relatedTarget) + // Public + + toggle(relatedTarget) { + return this._isShown ? this.hide() : this.show(relatedTarget) } - Modal.prototype.show = function (_relatedTarget) { - var that = this - var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) + show(relatedTarget) { + if (this._isShown || this._isTransitioning) { + return + } - this.$element.trigger(e) + if ($(this._element).hasClass(ClassName.FADE)) { + this._isTransitioning = true + } - if (this.isShown || e.isDefaultPrevented()) return + const showEvent = $.Event(Event.SHOW, { + relatedTarget + }) - this.isShown = true + $(this._element).trigger(showEvent) - this.checkScrollbar() - this.setScrollbar() - this.$body.addClass('modal-open') + if (this._isShown || showEvent.isDefaultPrevented()) { + return + } - this.escape() - this.resize() + this._isShown = true - this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) + this._checkScrollbar() + this._setScrollbar() - this.$dialog.on('mousedown.dismiss.bs.modal', function () { - that.$element.one('mouseup.dismiss.bs.modal', function (e) { - if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true + this._adjustDialog() + + this._setEscapeEvent() + this._setResizeEvent() + + $(this._element).on( + Event.CLICK_DISMISS, + Selector.DATA_DISMISS, + (event) => this.hide(event) + ) + + $(this._dialog).on(Event.MOUSEDOWN_DISMISS, () => { + $(this._element).one(Event.MOUSEUP_DISMISS, (event) => { + if ($(event.target).is(this._element)) { + this._ignoreBackdropClick = true + } }) }) - this.backdrop(function () { - var transition = $.support.transition && that.$element.hasClass('fade') + this._showBackdrop(() => this._showElement(relatedTarget)) + } - if (!that.$element.parent().length) { - that.$element.appendTo(that.$body) // don't move modals dom position - } + hide(event) { + if (event) { + event.preventDefault() + } - that.$element - .show() - .scrollTop(0) + if (!this._isShown || this._isTransitioning) { + return + } - that.adjustDialog() + const hideEvent = $.Event(Event.HIDE) - if (transition) { - that.$element[0].offsetWidth // force reflow - } + $(this._element).trigger(hideEvent) - that.$element.addClass('in') + if (!this._isShown || hideEvent.isDefaultPrevented()) { + return + } - that.enforceFocus() + this._isShown = false + const transition = $(this._element).hasClass(ClassName.FADE) - var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) + if (transition) { + this._isTransitioning = true + } - transition ? - that.$dialog // wait for modal to slide in - .one('bsTransitionEnd', function () { - that.$element.trigger('focus').trigger(e) - }) - .emulateTransitionEnd(Modal.TRANSITION_DURATION) : - that.$element.trigger('focus').trigger(e) - }) + this._setEscapeEvent() + this._setResizeEvent() + + $(document).off(Event.FOCUSIN) + + $(this._element).removeClass(ClassName.SHOW) + + $(this._element).off(Event.CLICK_DISMISS) + $(this._dialog).off(Event.MOUSEDOWN_DISMISS) + + + if (transition) { + const transitionDuration = Util.getTransitionDurationFromElement(this._element) + + $(this._element) + .one(Util.TRANSITION_END, (event) => this._hideModal(event)) + .emulateTransitionEnd(transitionDuration) + } else { + this._hideModal() + } + } + + dispose() { + [window, this._element, this._dialog] + .forEach((htmlElement) => $(htmlElement).off(EVENT_KEY)) + + /** + * `document` has 2 events `Event.FOCUSIN` and `Event.CLICK_DATA_API` + * Do not move `document` in `htmlElements` array + * It will remove `Event.CLICK_DATA_API` event that should remain + */ + $(document).off(Event.FOCUSIN) + + $.removeData(this._element, DATA_KEY) + + this._config = null + this._element = null + this._dialog = null + this._backdrop = null + this._isShown = null + this._isBodyOverflowing = null + this._ignoreBackdropClick = null + this._isTransitioning = null + this._scrollbarWidth = null + } + + handleUpdate() { + this._adjustDialog() } - Modal.prototype.hide = function (e) { - if (e) e.preventDefault() + // Private + + _getConfig(config) { + config = { + ...Default, + ...config + } + Util.typeCheckConfig(NAME, config, DefaultType) + return config + } + + _showElement(relatedTarget) { + const transition = $(this._element).hasClass(ClassName.FADE) + + if (!this._element.parentNode || + this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { + // Don't move modal's DOM position + document.body.appendChild(this._element) + } - e = $.Event('hide.bs.modal') + this._element.style.display = 'block' + this._element.removeAttribute('aria-hidden') + this._element.setAttribute('aria-modal', true) - this.$element.trigger(e) + if ($(this._dialog).hasClass(ClassName.SCROLLABLE)) { + this._dialog.querySelector(Selector.MODAL_BODY).scrollTop = 0 + } else { + this._element.scrollTop = 0 + } - if (!this.isShown || e.isDefaultPrevented()) return + if (transition) { + Util.reflow(this._element) + } - this.isShown = false + $(this._element).addClass(ClassName.SHOW) - this.escape() - this.resize() + if (this._config.focus) { + this._enforceFocus() + } - $(document).off('focusin.bs.modal') + const shownEvent = $.Event(Event.SHOWN, { + relatedTarget + }) - this.$element - .removeClass('in') - .off('click.dismiss.bs.modal') - .off('mouseup.dismiss.bs.modal') + const transitionComplete = () => { + if (this._config.focus) { + this._element.focus() + } + this._isTransitioning = false + $(this._element).trigger(shownEvent) + } - this.$dialog.off('mousedown.dismiss.bs.modal') + if (transition) { + const transitionDuration = Util.getTransitionDurationFromElement(this._dialog) - $.support.transition && this.$element.hasClass('fade') ? - this.$element - .one('bsTransitionEnd', $.proxy(this.hideModal, this)) - .emulateTransitionEnd(Modal.TRANSITION_DURATION) : - this.hideModal() + $(this._dialog) + .one(Util.TRANSITION_END, transitionComplete) + .emulateTransitionEnd(transitionDuration) + } else { + transitionComplete() + } } - Modal.prototype.enforceFocus = function () { + _enforceFocus() { $(document) - .off('focusin.bs.modal') // guard against infinite focus loop - .on('focusin.bs.modal', $.proxy(function (e) { - if (this.$element[0] !== e.target && !this.$element.has(e.target).length) { - this.$element.trigger('focus') + .off(Event.FOCUSIN) // Guard against infinite focus loop + .on(Event.FOCUSIN, (event) => { + if (document !== event.target && + this._element !== event.target && + $(this._element).has(event.target).length === 0) { + this._element.focus() } - }, this)) + }) } - Modal.prototype.escape = function () { - if (this.isShown && this.options.keyboard) { - this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) { - e.which == 27 && this.hide() - }, this)) - } else if (!this.isShown) { - this.$element.off('keydown.dismiss.bs.modal') + _setEscapeEvent() { + if (this._isShown && this._config.keyboard) { + $(this._element).on(Event.KEYDOWN_DISMISS, (event) => { + if (event.which === ESCAPE_KEYCODE) { + event.preventDefault() + this.hide() + } + }) + } else if (!this._isShown) { + $(this._element).off(Event.KEYDOWN_DISMISS) } } - Modal.prototype.resize = function () { - if (this.isShown) { - $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this)) + _setResizeEvent() { + if (this._isShown) { + $(window).on(Event.RESIZE, (event) => this.handleUpdate(event)) } else { - $(window).off('resize.bs.modal') + $(window).off(Event.RESIZE) } } - Modal.prototype.hideModal = function () { - var that = this - this.$element.hide() - this.backdrop(function () { - that.$body.removeClass('modal-open') - that.resetAdjustments() - that.resetScrollbar() - that.$element.trigger('hidden.bs.modal') + _hideModal() { + this._element.style.display = 'none' + this._element.setAttribute('aria-hidden', true) + this._element.removeAttribute('aria-modal') + this._isTransitioning = false + this._showBackdrop(() => { + $(document.body).removeClass(ClassName.OPEN) + this._resetAdjustments() + this._resetScrollbar() + $(this._element).trigger(Event.HIDDEN) }) } - Modal.prototype.removeBackdrop = function () { - this.$backdrop && this.$backdrop.remove() - this.$backdrop = null + _removeBackdrop() { + if (this._backdrop) { + $(this._backdrop).remove() + this._backdrop = null + } } - Modal.prototype.backdrop = function (callback) { - var that = this - var animate = this.$element.hasClass('fade') ? 'fade' : '' + _showBackdrop(callback) { + const animate = $(this._element).hasClass(ClassName.FADE) + ? ClassName.FADE : '' + + if (this._isShown && this._config.backdrop) { + this._backdrop = document.createElement('div') + this._backdrop.className = ClassName.BACKDROP - if (this.isShown && this.options.backdrop) { - var doAnimate = $.support.transition && animate + if (animate) { + this._backdrop.classList.add(animate) + } - this.$backdrop = $(document.createElement('div')) - .addClass('modal-backdrop ' + animate) - .appendTo(this.$body) + $(this._backdrop).appendTo(document.body) - this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) { - if (this.ignoreBackdropClick) { - this.ignoreBackdropClick = false + $(this._element).on(Event.CLICK_DISMISS, (event) => { + if (this._ignoreBackdropClick) { + this._ignoreBackdropClick = false return } - if (e.target !== e.currentTarget) return - this.options.backdrop == 'static' - ? this.$element[0].focus() - : this.hide() - }, this)) + if (event.target !== event.currentTarget) { + return + } + if (this._config.backdrop === 'static') { + this._element.focus() + } else { + this.hide() + } + }) - if (doAnimate) this.$backdrop[0].offsetWidth // force reflow + if (animate) { + Util.reflow(this._backdrop) + } - this.$backdrop.addClass('in') + $(this._backdrop).addClass(ClassName.SHOW) - if (!callback) return + if (!callback) { + return + } - doAnimate ? - this.$backdrop - .one('bsTransitionEnd', callback) - .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : + if (!animate) { callback() + return + } + + const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop) - } else if (!this.isShown && this.$backdrop) { - this.$backdrop.removeClass('in') + $(this._backdrop) + .one(Util.TRANSITION_END, callback) + .emulateTransitionEnd(backdropTransitionDuration) + } else if (!this._isShown && this._backdrop) { + $(this._backdrop).removeClass(ClassName.SHOW) - var callbackRemove = function () { - that.removeBackdrop() - callback && callback() + const callbackRemove = () => { + this._removeBackdrop() + if (callback) { + callback() + } } - $.support.transition && this.$element.hasClass('fade') ? - this.$backdrop - .one('bsTransitionEnd', callbackRemove) - .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : - callbackRemove() + if ($(this._element).hasClass(ClassName.FADE)) { + const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop) + + $(this._backdrop) + .one(Util.TRANSITION_END, callbackRemove) + .emulateTransitionEnd(backdropTransitionDuration) + } else { + callbackRemove() + } } else if (callback) { callback() } } - // these following methods are used to handle overflowing modals + // ---------------------------------------------------------------------- + // the following methods are used to handle overflowing modals + // todo (fat): these should probably be refactored out of modal.js + // ---------------------------------------------------------------------- - Modal.prototype.handleUpdate = function () { - this.adjustDialog() - } + _adjustDialog() { + const isModalOverflowing = + this._element.scrollHeight > document.documentElement.clientHeight - Modal.prototype.adjustDialog = function () { - var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight + if (!this._isBodyOverflowing && isModalOverflowing) { + this._element.style.paddingLeft = `${this._scrollbarWidth}px` + } - this.$element.css({ - paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '', - paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : '' - }) + if (this._isBodyOverflowing && !isModalOverflowing) { + this._element.style.paddingRight = `${this._scrollbarWidth}px` + } } - Modal.prototype.resetAdjustments = function () { - this.$element.css({ - paddingLeft: '', - paddingRight: '' - }) + _resetAdjustments() { + this._element.style.paddingLeft = '' + this._element.style.paddingRight = '' } - Modal.prototype.checkScrollbar = function () { - var fullWindowWidth = window.innerWidth - if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8 - var documentElementRect = document.documentElement.getBoundingClientRect() - fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left) - } - this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth - this.scrollbarWidth = this.measureScrollbar() + _checkScrollbar() { + const rect = document.body.getBoundingClientRect() + this._isBodyOverflowing = rect.left + rect.right < window.innerWidth + this._scrollbarWidth = this._getScrollbarWidth() } - Modal.prototype.setScrollbar = function () { - var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10) - this.originalBodyPad = document.body.style.paddingRight || '' - if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth) + _setScrollbar() { + if (this._isBodyOverflowing) { + // Note: DOMNode.style.paddingRight returns the actual value or '' if not set + // while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set + const fixedContent = [].slice.call(document.querySelectorAll(Selector.FIXED_CONTENT)) + const stickyContent = [].slice.call(document.querySelectorAll(Selector.STICKY_CONTENT)) + + // Adjust fixed content padding + $(fixedContent).each((index, element) => { + const actualPadding = element.style.paddingRight + const calculatedPadding = $(element).css('padding-right') + $(element) + .data('padding-right', actualPadding) + .css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`) + }) + + // Adjust sticky content margin + $(stickyContent).each((index, element) => { + const actualMargin = element.style.marginRight + const calculatedMargin = $(element).css('margin-right') + $(element) + .data('margin-right', actualMargin) + .css('margin-right', `${parseFloat(calculatedMargin) - this._scrollbarWidth}px`) + }) + + // Adjust body padding + const actualPadding = document.body.style.paddingRight + const calculatedPadding = $(document.body).css('padding-right') + $(document.body) + .data('padding-right', actualPadding) + .css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`) + } + + $(document.body).addClass(ClassName.OPEN) } - Modal.prototype.resetScrollbar = function () { - this.$body.css('padding-right', this.originalBodyPad) + _resetScrollbar() { + // Restore fixed content padding + const fixedContent = [].slice.call(document.querySelectorAll(Selector.FIXED_CONTENT)) + $(fixedContent).each((index, element) => { + const padding = $(element).data('padding-right') + $(element).removeData('padding-right') + element.style.paddingRight = padding ? padding : '' + }) + + // Restore sticky content + const elements = [].slice.call(document.querySelectorAll(`${Selector.STICKY_CONTENT}`)) + $(elements).each((index, element) => { + const margin = $(element).data('margin-right') + if (typeof margin !== 'undefined') { + $(element).css('margin-right', margin).removeData('margin-right') + } + }) + + // Restore body padding + const padding = $(document.body).data('padding-right') + $(document.body).removeData('padding-right') + document.body.style.paddingRight = padding ? padding : '' } - Modal.prototype.measureScrollbar = function () { // thx walsh - var scrollDiv = document.createElement('div') - scrollDiv.className = 'modal-scrollbar-measure' - this.$body.append(scrollDiv) - var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth - this.$body[0].removeChild(scrollDiv) + _getScrollbarWidth() { // thx d.walsh + const scrollDiv = document.createElement('div') + scrollDiv.className = ClassName.SCROLLBAR_MEASURER + document.body.appendChild(scrollDiv) + const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth + document.body.removeChild(scrollDiv) return scrollbarWidth } + // Static - // MODAL PLUGIN DEFINITION - // ======================= - - function Plugin(option, _relatedTarget) { + static _jQueryInterface(config, relatedTarget) { return this.each(function () { - var $this = $(this) - var data = $this.data('bs.modal') - var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) + let data = $(this).data(DATA_KEY) + const _config = { + ...Default, + ...$(this).data(), + ...typeof config === 'object' && config ? config : {} + } + + if (!data) { + data = new Modal(this, _config) + $(this).data(DATA_KEY, data) + } - if (!data) $this.data('bs.modal', (data = new Modal(this, options))) - if (typeof option == 'string') data[option](_relatedTarget) - else if (options.show) data.show(_relatedTarget) + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`) + } + data[config](relatedTarget) + } else if (_config.show) { + data.show(relatedTarget) + } }) } +} - var old = $.fn.modal +/** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ - $.fn.modal = Plugin - $.fn.modal.Constructor = Modal +$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { + let target + const selector = Util.getSelectorFromElement(this) + if (selector) { + target = document.querySelector(selector) + } - // MODAL NO CONFLICT - // ================= + const config = $(target).data(DATA_KEY) + ? 'toggle' : { + ...$(target).data(), + ...$(this).data() + } - $.fn.modal.noConflict = function () { - $.fn.modal = old - return this + if (this.tagName === 'A' || this.tagName === 'AREA') { + event.preventDefault() } + const $target = $(target).one(Event.SHOW, (showEvent) => { + if (showEvent.isDefaultPrevented()) { + // Only register focus restorer if modal will actually get shown + return + } - // MODAL DATA-API - // ============== + $target.one(Event.HIDDEN, () => { + if ($(this).is(':visible')) { + this.focus() + } + }) + }) - $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { - var $this = $(this) - var href = $this.attr('href') - var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7 - var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) + Modal._jQueryInterface.call($(target), config, this) +}) - if ($this.is('a')) e.preventDefault() +/** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ - $target.one('show.bs.modal', function (showEvent) { - if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown - $target.one('hidden.bs.modal', function () { - $this.is(':visible') && $this.trigger('focus') - }) - }) - Plugin.call($target, option, this) - }) +$.fn[NAME] = Modal._jQueryInterface +$.fn[NAME].Constructor = Modal +$.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Modal._jQueryInterface +} -}(jQuery); +export default Modal diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/popover.js b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/popover.js index aef22d16d6e..98f2f3fbef1 100644 --- a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/popover.js +++ b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/popover.js @@ -1,108 +1,184 @@ -/* ======================================================================== - * Bootstrap: popover.js v3.3.5 - * http://getbootstrap.com/javascript/#popovers - * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.3.1): popover.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // POPOVER PUBLIC CLASS DEFINITION - // =============================== - - var Popover = function (element, options) { - this.init('popover', element, options) + * -------------------------------------------------------------------------- + */ + +import $ from 'jquery' +import Tooltip from './tooltip' + +/** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + +const NAME = 'popover' +const VERSION = '4.3.1' +const DATA_KEY = 'bs.popover' +const EVENT_KEY = `.${DATA_KEY}` +const JQUERY_NO_CONFLICT = $.fn[NAME] +const CLASS_PREFIX = 'bs-popover' +const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g') + +const Default = { + ...Tooltip.Default, + placement : 'right', + trigger : 'click', + content : '', + template : '' +} + +const DefaultType = { + ...Tooltip.DefaultType, + content : '(string|element|function)' +} + +const ClassName = { + FADE : 'fade', + SHOW : 'show' +} + +const Selector = { + TITLE : '.popover-header', + CONTENT : '.popover-body' +} + +const Event = { + HIDE : `hide${EVENT_KEY}`, + HIDDEN : `hidden${EVENT_KEY}`, + SHOW : `show${EVENT_KEY}`, + SHOWN : `shown${EVENT_KEY}`, + INSERTED : `inserted${EVENT_KEY}`, + CLICK : `click${EVENT_KEY}`, + FOCUSIN : `focusin${EVENT_KEY}`, + FOCUSOUT : `focusout${EVENT_KEY}`, + MOUSEENTER : `mouseenter${EVENT_KEY}`, + MOUSELEAVE : `mouseleave${EVENT_KEY}` +} + +/** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + +class Popover extends Tooltip { + // Getters + + static get VERSION() { + return VERSION } - if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') - - Popover.VERSION = '3.3.5' - - Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { - placement: 'right', - trigger: 'click', - content: '', - template: '' - }) - - - // NOTE: POPOVER EXTENDS tooltip.js - // ================================ - - Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) - - Popover.prototype.constructor = Popover - - Popover.prototype.getDefaults = function () { - return Popover.DEFAULTS + static get Default() { + return Default } - Popover.prototype.setContent = function () { - var $tip = this.tip() - var title = this.getTitle() - var content = this.getContent() + static get NAME() { + return NAME + } - $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) - $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events - this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' - ](content) + static get DATA_KEY() { + return DATA_KEY + } - $tip.removeClass('fade top bottom left right in') + static get Event() { + return Event + } - // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do - // this manually by checking the contents. - if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() + static get EVENT_KEY() { + return EVENT_KEY } - Popover.prototype.hasContent = function () { - return this.getTitle() || this.getContent() + static get DefaultType() { + return DefaultType } - Popover.prototype.getContent = function () { - var $e = this.$element - var o = this.options + // Overrides - return $e.attr('data-content') - || (typeof o.content == 'function' ? - o.content.call($e[0]) : - o.content) + isWithContent() { + return this.getTitle() || this._getContent() } - Popover.prototype.arrow = function () { - return (this.$arrow = this.$arrow || this.tip().find('.arrow')) + addAttachmentClass(attachment) { + $(this.getTipElement()).addClass(`${CLASS_PREFIX}-${attachment}`) } + getTipElement() { + this.tip = this.tip || $(this.config.template)[0] + return this.tip + } - // POPOVER PLUGIN DEFINITION - // ========================= + setContent() { + const $tip = $(this.getTipElement()) - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.popover') - var options = typeof option == 'object' && option + // We use append for html objects to maintain js events + this.setElementContent($tip.find(Selector.TITLE), this.getTitle()) + let content = this._getContent() + if (typeof content === 'function') { + content = content.call(this.element) + } + this.setElementContent($tip.find(Selector.CONTENT), content) - if (!data && /destroy|hide/.test(option)) return - if (!data) $this.data('bs.popover', (data = new Popover(this, options))) - if (typeof option == 'string') data[option]() - }) + $tip.removeClass(`${ClassName.FADE} ${ClassName.SHOW}`) } - var old = $.fn.popover + // Private - $.fn.popover = Plugin - $.fn.popover.Constructor = Popover + _getContent() { + return this.element.getAttribute('data-content') || + this.config.content + } + _cleanTipClass() { + const $tip = $(this.getTipElement()) + const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX) + if (tabClass !== null && tabClass.length > 0) { + $tip.removeClass(tabClass.join('')) + } + } - // POPOVER NO CONFLICT - // =================== + // Static - $.fn.popover.noConflict = function () { - $.fn.popover = old - return this + static _jQueryInterface(config) { + return this.each(function () { + let data = $(this).data(DATA_KEY) + const _config = typeof config === 'object' ? config : null + + if (!data && /dispose|hide/.test(config)) { + return + } + + if (!data) { + data = new Popover(this, _config) + $(this).data(DATA_KEY, data) + } + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`) + } + data[config]() + } + }) } - -}(jQuery); +} + +/** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + +$.fn[NAME] = Popover._jQueryInterface +$.fn[NAME].Constructor = Popover +$.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Popover._jQueryInterface +} + +export default Popover diff --git a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/scrollspy.js b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/scrollspy.js index 7208e250688..e8cd6bf98c2 100644 --- a/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/scrollspy.js +++ b/src/Orchard.Web/Modules/Orchard.Resources/Assets/Js/Bootstrap/scrollspy.js @@ -1,172 +1,326 @@ -/* ======================================================================== - * Bootstrap: scrollspy.js v3.3.5 - * http://getbootstrap.com/javascript/#scrollspy - * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.3.1): scrollspy.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ + * -------------------------------------------------------------------------- + */ + +import $ from 'jquery' +import Util from './util' + +/** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + +const NAME = 'scrollspy' +const VERSION = '4.3.1' +const DATA_KEY = 'bs.scrollspy' +const EVENT_KEY = `.${DATA_KEY}` +const DATA_API_KEY = '.data-api' +const JQUERY_NO_CONFLICT = $.fn[NAME] + +const Default = { + offset : 10, + method : 'auto', + target : '' +} + +const DefaultType = { + offset : 'number', + method : 'string', + target : '(string|element)' +} + +const Event = { + ACTIVATE : `activate${EVENT_KEY}`, + SCROLL : `scroll${EVENT_KEY}`, + LOAD_DATA_API : `load${EVENT_KEY}${DATA_API_KEY}` +} + +const ClassName = { + DROPDOWN_ITEM : 'dropdown-item', + DROPDOWN_MENU : 'dropdown-menu', + ACTIVE : 'active' +} + +const Selector = { + DATA_SPY : '[data-spy="scroll"]', + ACTIVE : '.active', + NAV_LIST_GROUP : '.nav, .list-group', + NAV_LINKS : '.nav-link', + NAV_ITEMS : '.nav-item', + LIST_ITEMS : '.list-group-item', + DROPDOWN : '.dropdown', + DROPDOWN_ITEMS : '.dropdown-item', + DROPDOWN_TOGGLE : '.dropdown-toggle' +} + +const OffsetMethod = { + OFFSET : 'offset', + POSITION : 'position' +} + +/** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + +class ScrollSpy { + constructor(element, config) { + this._element = element + this._scrollElement = element.tagName === 'BODY' ? window : element + this._config = this._getConfig(config) + this._selector = `${this._config.target} ${Selector.NAV_LINKS},` + + `${this._config.target} ${Selector.LIST_ITEMS},` + + `${this._config.target} ${Selector.DROPDOWN_ITEMS}` + this._offsets = [] + this._targets = [] + this._activeTarget = null + this._scrollHeight = 0 + + $(this._scrollElement).on(Event.SCROLL, (event) => this._process(event)) + this.refresh() + this._process() + } -+function ($) { - 'use strict'; - - // SCROLLSPY CLASS DEFINITION - // ========================== + // Getters - function ScrollSpy(element, options) { - this.$body = $(document.body) - this.$scrollElement = $(element).is(document.body) ? $(window) : $(element) - this.options = $.extend({}, ScrollSpy.DEFAULTS, options) - this.selector = (this.options.target || '') + ' .nav li > a' - this.offsets = [] - this.targets = [] - this.activeTarget = null - this.scrollHeight = 0 + static get VERSION() { + return VERSION + } - this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this)) - this.refresh() - this.process() + static get Default() { + return Default } - ScrollSpy.VERSION = '3.3.5' + // Public + + refresh() { + const autoMethod = this._scrollElement === this._scrollElement.window + ? OffsetMethod.OFFSET : OffsetMethod.POSITION + + const offsetMethod = this._config.method === 'auto' + ? autoMethod : this._config.method + + const offsetBase = offsetMethod === OffsetMethod.POSITION + ? this._getScrollTop() : 0 + + this._offsets = [] + this._targets = [] + + this._scrollHeight = this._getScrollHeight() - ScrollSpy.DEFAULTS = { - offset: 10 + const targets = [].slice.call(document.querySelectorAll(this._selector)) + + targets + .map((element) => { + let target + const targetSelector = Util.getSelectorFromElement(element) + + if (targetSelector) { + target = document.querySelector(targetSelector) + } + + if (target) { + const targetBCR = target.getBoundingClientRect() + if (targetBCR.width || targetBCR.height) { + // TODO (fat): remove sketch reliance on jQuery position/offset + return [ + $(target)[offsetMethod]().top + offsetBase, + targetSelector + ] + } + } + return null + }) + .filter((item) => item) + .sort((a, b) => a[0] - b[0]) + .forEach((item) => { + this._offsets.push(item[0]) + this._targets.push(item[1]) + }) } - ScrollSpy.prototype.getScrollHeight = function () { - return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight) + dispose() { + $.removeData(this._element, DATA_KEY) + $(this._scrollElement).off(EVENT_KEY) + + this._element = null + this._scrollElement = null + this._config = null + this._selector = null + this._offsets = null + this._targets = null + this._activeTarget = null + this._scrollHeight = null } - ScrollSpy.prototype.refresh = function () { - var that = this - var offsetMethod = 'offset' - var offsetBase = 0 + // Private - this.offsets = [] - this.targets = [] - this.scrollHeight = this.getScrollHeight() + _getConfig(config) { + config = { + ...Default, + ...typeof config === 'object' && config ? config : {} + } - if (!$.isWindow(this.$scrollElement[0])) { - offsetMethod = 'position' - offsetBase = this.$scrollElement.scrollTop() + if (typeof config.target !== 'string') { + let id = $(config.target).attr('id') + if (!id) { + id = Util.getUID(NAME) + $(config.target).attr('id', id) + } + config.target = `#${id}` } - this.$body - .find(this.selector) - .map(function () { - var $el = $(this) - var href = $el.data('target') || $el.attr('href') - var $href = /^#./.test(href) && $(href) - - return ($href - && $href.length - && $href.is(':visible') - && [[$href[offsetMethod]().top + offsetBase, href]]) || null - }) - .sort(function (a, b) { return a[0] - b[0] }) - .each(function () { - that.offsets.push(this[0]) - that.targets.push(this[1]) - }) + Util.typeCheckConfig(NAME, config, DefaultType) + + return config } - ScrollSpy.prototype.process = function () { - var scrollTop = this.$scrollElement.scrollTop() + this.options.offset - var scrollHeight = this.getScrollHeight() - var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height() - var offsets = this.offsets - var targets = this.targets - var activeTarget = this.activeTarget - var i + _getScrollTop() { + return this._scrollElement === window + ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop + } + + _getScrollHeight() { + return this._scrollElement.scrollHeight || Math.max( + document.body.scrollHeight, + document.documentElement.scrollHeight + ) + } + + _getOffsetHeight() { + return this._scrollElement === window + ? window.innerHeight : this._scrollElement.getBoundingClientRect().height + } - if (this.scrollHeight != scrollHeight) { + _process() { + const scrollTop = this._getScrollTop() + this._config.offset + const scrollHeight = this._getScrollHeight() + const maxScroll = this._config.offset + + scrollHeight - + this._getOffsetHeight() + + if (this._scrollHeight !== scrollHeight) { this.refresh() } if (scrollTop >= maxScroll) { - return activeTarget != (i = targets[targets.length - 1]) && this.activate(i) + const target = this._targets[this._targets.length - 1] + + if (this._activeTarget !== target) { + this._activate(target) + } + return } - if (activeTarget && scrollTop < offsets[0]) { - this.activeTarget = null - return this.clear() + if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) { + this._activeTarget = null + this._clear() + return } - for (i = offsets.length; i--;) { - activeTarget != targets[i] - && scrollTop >= offsets[i] - && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1]) - && this.activate(targets[i]) + const offsetLength = this._offsets.length + for (let i = offsetLength; i--;) { + const isActiveTarget = this._activeTarget !== this._targets[i] && + scrollTop >= this._offsets[i] && + (typeof this._offsets[i + 1] === 'undefined' || + scrollTop < this._offsets[i + 1]) + + if (isActiveTarget) { + this._activate(this._targets[i]) + } } } - ScrollSpy.prototype.activate = function (target) { - this.activeTarget = target + _activate(target) { + this._activeTarget = target - this.clear() + this._clear() - var selector = this.selector + - '[data-target="' + target + '"],' + - this.selector + '[href="' + target + '"]' + const queries = this._selector + .split(',') + .map((selector) => `${selector}[data-target="${target}"],${selector}[href="${target}"]`) - var active = $(selector) - .parents('li') - .addClass('active') + const $link = $([].slice.call(document.querySelectorAll(queries.join(',')))) - if (active.parent('.dropdown-menu').length) { - active = active - .closest('li.dropdown') - .addClass('active') + if ($link.hasClass(ClassName.DROPDOWN_ITEM)) { + $link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE) + $link.addClass(ClassName.ACTIVE) + } else { + // Set triggered link as active + $link.addClass(ClassName.ACTIVE) + // Set triggered links parents as active + // With both
          and