diff --git a/.github/workflows/codeql-config.yml b/.github/config/codeql-config.yml similarity index 100% rename from .github/workflows/codeql-config.yml rename to .github/config/codeql-config.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 3d08bf3a4b27..ee912262d7fb 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,7 +56,7 @@ jobs: - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 with: - config-file: ./.github/workflows/codeql-config.yml + config-file: ./.github/config/codeql-config.yml # This job is to prevent the workflow status from showing as failed when all other jobs are skipped - See https://github.community/t/workflow-is-failing-if-no-job-can-be-ran-due-to-condition/16873 always_job: diff --git a/build/NuSpecs/buildTransitive/Umbraco.Cms.StaticAssets.targets b/build/NuSpecs/buildTransitive/Umbraco.Cms.StaticAssets.targets index d271653e4448..f9ee41e13988 100644 --- a/build/NuSpecs/buildTransitive/Umbraco.Cms.StaticAssets.targets +++ b/build/NuSpecs/buildTransitive/Umbraco.Cms.StaticAssets.targets @@ -6,6 +6,16 @@ umbraco + + $(DefaultItemExcludes);App_Plugins\**; + + $(DefaultItemExcludes);umbraco\Data\**; + $(DefaultItemExcludes);umbraco\Logs\**; + $(DefaultItemExcludes);umbraco\mediacache\**; + + $(DefaultItemExcludes);wwwroot\media\**; + + @@ -21,7 +31,42 @@ SourceFiles="@(ContentWwwrootFiles)" DestinationFiles="@(ContentWwwrootFiles->'$(MSBuildProjectDirectory)\wwwroot\$(UmbracoWwwrootName)\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="true" /> + + + + + <_AppPluginsFiles Include="App_Plugins\**" /> + + + + + + + + <_UmbracoFolderFiles Include="umbraco\config\**" /> + <_UmbracoFolderFiles Include="umbraco\PartialViewMacros\**" /> + <_UmbracoFolderFiles Include="umbraco\UmbracoBackOffice\**" /> + <_UmbracoFolderFiles Include="umbraco\UmbracoInstall\**" /> + <_UmbracoFolderFiles Include="umbraco\UmbracoWebsite\**" /> + <_UmbracoFolderFiles Include="umbraco\UmbracoWebsite\**" /> + <_UmbracoFolderFiles Include="umbraco\Licenses\**" /> + + + <_UmbracoFolderFiles Include="umbraco\Deploy\**" /> + + + diff --git a/build/azure-pipelines.yml b/build/azure-pipelines.yml index 988265eb5d63..582fadfc49c4 100644 --- a/build/azure-pipelines.yml +++ b/build/azure-pipelines.yml @@ -226,14 +226,14 @@ stages: inputs: command: ci workingDir: 'tests\Umbraco.Tests.AcceptanceTest' - - task: Npm@1 + - task: PowerShell@2 displayName: Run Cypress (Desktop) condition: always() continueOnError: true inputs: - workingDir: tests\Umbraco.Tests.AcceptanceTest - command: 'custom' - customCommand: 'run test -- --reporter junit --reporter-options "mochaFile=results/test-output-D-[hash].xml,toConsole=true" --config="viewportHeight=1600,viewportWidth=2560,screenshotsFolder=cypress/artifacts/desktop/screenshots,videosFolder=cypress/artifacts/desktop/videos,videoUploadOnPasses=false"' + targetType: inline + workingDirectory: tests\Umbraco.Tests.AcceptanceTest + script: 'npm run test -- --reporter junit --reporter-options "mochaFile=results/test-output-D-[hash].xml,toConsole=true" --config="viewportHeight=1600,viewportWidth=2560,screenshotsFolder=cypress/artifacts/desktop/screenshots,videosFolder=cypress/artifacts/desktop/videos,videoUploadOnPasses=false"' - task: PublishTestResults@2 condition: always() @@ -329,14 +329,14 @@ stages: inputs: command: ci workingDir: 'tests/Umbraco.Tests.AcceptanceTest' - - task: Npm@1 + - task: Bash@3 displayName: Run Cypress (Desktop) condition: always() continueOnError: true inputs: - workingDir: tests/Umbraco.Tests.AcceptanceTest - command: 'custom' - customCommand: 'run test -- --reporter junit --reporter-options "mochaFile=results/test-output-D-[hash].xml,toConsole=true" --config="viewportHeight=1600,viewportWidth=2560,screenshotsFolder=cypress/artifacts/desktop/screenshots,videosFolder=cypress/artifacts/desktop/videos,videoUploadOnPasses=false"' + targetType: inline + workingDirectory: tests/Umbraco.Tests.AcceptanceTest + script: 'npm run test -- --reporter junit --reporter-options "mochaFile=results/test-output-D-[hash].xml,toConsole=true" --config="viewportHeight=1600,viewportWidth=2560,screenshotsFolder=cypress/artifacts/desktop/screenshots,videosFolder=cypress/artifacts/desktop/videos,videoUploadOnPasses=false"' - task: PublishTestResults@2 condition: always() inputs: diff --git a/build/templates/UmbracoProject/UmbracoProject.csproj b/build/templates/UmbracoProject/UmbracoProject.csproj index 99e72bae0f5e..1b3290927d36 100644 --- a/build/templates/UmbracoProject/UmbracoProject.csproj +++ b/build/templates/UmbracoProject/UmbracoProject.csproj @@ -3,9 +3,6 @@ net5.0 Umbraco.Cms.Web.UI - $(DefaultItemExcludes);App_Plugins/**; - $(DefaultItemExcludes);umbraco/**; - $(DefaultItemExcludes);wwwroot/media/**; @@ -26,16 +23,6 @@ - - - - - - - - - - true diff --git a/src/JsonSchema/AppSettings.cs b/src/JsonSchema/AppSettings.cs index 1b7c6d46fc37..4af6685d8a7e 100644 --- a/src/JsonSchema/AppSettings.cs +++ b/src/JsonSchema/AppSettings.cs @@ -1,82 +1,120 @@ -using Umbraco.Cms.Core.Configuration.Models; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Forms.Core.Configuration; using SecuritySettings = Umbraco.Cms.Core.Configuration.Models.SecuritySettings; namespace JsonSchema { - public class AppSettings + internal class AppSettings { + /// + /// Gets or sets the Umbraco + /// public UmbracoDefinition Umbraco { get; set; } /// - /// Configuration of Umbraco CMS and packages + /// Configuration of Umbraco CMS and packages /// - public class UmbracoDefinition + internal class UmbracoDefinition { + // ReSharper disable once InconsistentNaming public CmsDefinition CMS { get; set; } + public FormsDefinition Forms { get; set; } + public DeployDefinition Deploy { get; set; } /// - /// Configurations for the Umbraco CMS + /// Configurations for the Umbraco CMS /// public class CmsDefinition { public ActiveDirectorySettings ActiveDirectory { get; set; } + public ContentSettings Content { get; set; } + public ExceptionFilterSettings ExceptionFilter { get; set; } + public ModelsBuilderSettings ModelsBuilder { get; set; } + public GlobalSettings Global { get; set; } + public HealthChecksSettings HealthChecks { get; set; } + public HostingSettings Hosting { get; set; } + public ImagingSettings Imaging { get; set; } + public IndexCreatorSettings Examine { get; set; } + public KeepAliveSettings KeepAlive { get; set; } + public LoggingSettings Logging { get; set; } + public MemberPasswordConfigurationSettings MemberPassword { get; set; } + public NuCacheSettings NuCache { get; set; } + public RequestHandlerSettings RequestHandler { get; set; } + public RuntimeSettings Runtime { get; set; } + public SecuritySettings Security { get; set; } + public TourSettings Tours { get; set; } + public TypeFinderSettings TypeFinder { get; set; } + public UserPasswordConfigurationSettings UserPassword { get; set; } + public WebRoutingSettings WebRouting { get; set; } + public UmbracoPluginSettings Plugins { get; set; } + public UnattendedSettings Unattended { get; set; } + public RichTextEditorSettings RichTextEditor { get; set; } + public RuntimeMinificationSettings RuntimeMinification { get; set; } + public BasicAuthSettings BasicAuth { get; set; } + public PackageMigrationSettings PackageMigration { get; set; } } /// - /// Configurations for the Umbraco Forms package to Umbraco CMS + /// Configurations for the Umbraco Forms package to Umbraco CMS /// public class FormsDefinition { public FormDesignSettings FormDesign { get; set; } + public PackageOptionSettings Options { get; set; } + public Umbraco.Forms.Core.Configuration.SecuritySettings Security { get; set; } + public FieldTypesDefinition FieldTypes { get; set; } /// - /// Configurations for the Umbraco Forms Field Types + /// Configurations for the Umbraco Forms Field Types /// public class FieldTypesDefinition { public DatePickerSettings DatePicker { get; set; } + public Recaptcha2Settings Recaptcha2 { get; set; } + public Recaptcha3Settings Recaptcha3 { get; set; } } } /// - /// Configurations for the Umbraco Deploy package to Umbraco CMS + /// Configurations for the Umbraco Deploy package to Umbraco CMS /// public class DeployDefinition { - } } } diff --git a/src/JsonSchema/JsonSchema.csproj b/src/JsonSchema/JsonSchema.csproj index 3b64612b62ce..942bdd970556 100644 --- a/src/JsonSchema/JsonSchema.csproj +++ b/src/JsonSchema/JsonSchema.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/JsonSchema/NamespacePrefixedSchemaNameGenerator.cs b/src/JsonSchema/NamespacePrefixedSchemaNameGenerator.cs index 77b7b8c47445..54ce0fdedfdf 100644 --- a/src/JsonSchema/NamespacePrefixedSchemaNameGenerator.cs +++ b/src/JsonSchema/NamespacePrefixedSchemaNameGenerator.cs @@ -1,13 +1,13 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using NJsonSchema.Generation; namespace JsonSchema { - public class NamespacePrefixedSchemaNameGenerator : DefaultSchemaNameGenerator + internal class NamespacePrefixedSchemaNameGenerator : DefaultSchemaNameGenerator { - public override string Generate(Type type) - { - return type.Namespace.Replace(".", String.Empty) + base.Generate(type); - } + public override string Generate(Type type) => type.Namespace.Replace(".", string.Empty) + base.Generate(type); } } diff --git a/src/JsonSchema/Options.cs b/src/JsonSchema/Options.cs new file mode 100644 index 000000000000..9930210cd884 --- /dev/null +++ b/src/JsonSchema/Options.cs @@ -0,0 +1,13 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using CommandLine; + +namespace JsonSchema +{ + internal class Options + { + [Option('o', "outputFile", Required = false, HelpText = "Set path of the output file.", Default = "../../../../Umbraco.Web.UI/umbraco/config/appsettings-schema.json")] + public string OutputFile { get; set; } + } +} diff --git a/src/JsonSchema/Program.cs b/src/JsonSchema/Program.cs index cd0909302060..8b02068c46ed 100644 --- a/src/JsonSchema/Program.cs +++ b/src/JsonSchema/Program.cs @@ -1,3 +1,6 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + using System; using System.IO; using System.Threading.Tasks; @@ -5,14 +8,8 @@ namespace JsonSchema { - class Program + internal class Program { - private class Options - { - [Option('o', "outputFile", Required = false, HelpText = "Set path of the output file.", Default = "../../../../Umbraco.Web.UI/umbraco/config/appsettings-schema.json")] - public string OutputFile { get; set; } - } - public static async Task Main(string[] args) { try @@ -25,7 +22,6 @@ await Parser.Default.ParseArguments(args) Console.WriteLine(e); throw; } - } private static async Task Execute(Options options) @@ -34,7 +30,7 @@ private static async Task Execute(Options options) var schema = await generator.Generate(); var path = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, options.OutputFile)); - Console.WriteLine("Path to use {0}",path); + Console.WriteLine("Path to use {0}", path); Directory.CreateDirectory(Path.GetDirectoryName(path)); Console.WriteLine("Ensured directory exists"); await File.WriteAllTextAsync(path, schema); diff --git a/src/JsonSchema/UmbracoJsonSchemaGenerator.cs b/src/JsonSchema/UmbracoJsonSchemaGenerator.cs index b6e516d0c5ec..e06189d3b432 100644 --- a/src/JsonSchema/UmbracoJsonSchemaGenerator.cs +++ b/src/JsonSchema/UmbracoJsonSchemaGenerator.cs @@ -1,4 +1,7 @@ -using System.Net.Http; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Net.Http; using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -7,28 +10,26 @@ namespace JsonSchema { /// - /// Generator of the JsonSchema for AppSettings.json including A specific Umbraco version. + /// Generator of the JsonSchema for AppSettings.json including A specific Umbraco version. /// public class UmbracoJsonSchemaGenerator { + private static readonly HttpClient s_client = new (); private readonly JsonSchemaGenerator _innerGenerator; - private static readonly HttpClient s_client = new HttpClient(); /// - /// Creates a new instance of . + /// Initializes a new instance of the class. /// - /// The prefix to use for definitions generated. public UmbracoJsonSchemaGenerator() => _innerGenerator = new JsonSchemaGenerator(new UmbracoJsonSchemaGeneratorSettings()); - /// - /// Generates a json representing the JsonSchema for AppSettings.json including A specific Umbraco version.. + /// Generates a json representing the JsonSchema for AppSettings.json including A specific Umbraco version.. /// public async Task Generate() { - var umbracoSchema = GenerateUmbracoSchema(); - var officialSchema = await GetOfficialAppSettingsSchema(); + JObject umbracoSchema = GenerateUmbracoSchema(); + JObject officialSchema = await GetOfficialAppSettingsSchema(); officialSchema.Merge(umbracoSchema); @@ -37,19 +38,17 @@ public async Task Generate() private async Task GetOfficialAppSettingsSchema() { + HttpResponseMessage response = await s_client.GetAsync("https://json.schemastore.org/appsettings.json") + .ConfigureAwait(false); - var response = await s_client.GetAsync("https://json.schemastore.org/appsettings.json"); - - - var result = await response.Content.ReadAsStringAsync(); + var result = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject(result); - } private JObject GenerateUmbracoSchema() { - var schema = _innerGenerator.Generate(typeof(AppSettings)); + NJsonSchema.JsonSchema schema = _innerGenerator.Generate(typeof(AppSettings)); return JsonConvert.DeserializeObject(schema.ToJson()); } diff --git a/src/JsonSchema/UmbracoJsonSchemaGeneratorSettings.cs b/src/JsonSchema/UmbracoJsonSchemaGeneratorSettings.cs index 26af0faae2db..46625aeb2cdd 100644 --- a/src/JsonSchema/UmbracoJsonSchemaGeneratorSettings.cs +++ b/src/JsonSchema/UmbracoJsonSchemaGeneratorSettings.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; @@ -12,15 +15,14 @@ namespace JsonSchema public class UmbracoJsonSchemaGeneratorSettings : JsonSchemaGeneratorSettings { /// - /// Creates a new instance of . + /// Initializes a new instance of the class. /// - /// The prefix to use for definitions generated. public UmbracoJsonSchemaGeneratorSettings() { AlwaysAllowAdditionalObjectProperties = true; SerializerSettings = new JsonSerializerSettings() { - ContractResolver = new WritablePropertiesOnlyResolver() + ContractResolver = new WritablePropertiesOnlyResolver() }; DefaultReferenceTypeNullHandling = ReferenceTypeNullHandling.NotNull; SchemaNameGenerator = new NamespacePrefixedSchemaNameGenerator(); diff --git a/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs b/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs index ddd9f96c73a2..670574896ee1 100644 --- a/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs +++ b/src/Umbraco.Core/Cache/FastDictionaryAppCache.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -18,6 +18,8 @@ public class FastDictionaryAppCache : IAppCache /// private readonly ConcurrentDictionary> _items = new ConcurrentDictionary>(); + public IEnumerable Keys => _items.Keys; + public int Count => _items.Count; /// diff --git a/src/Umbraco.Core/Exceptions/InvalidCompositionException.cs b/src/Umbraco.Core/Exceptions/InvalidCompositionException.cs index 4fb335be847d..21e5cc03ed86 100644 --- a/src/Umbraco.Core/Exceptions/InvalidCompositionException.cs +++ b/src/Umbraco.Core/Exceptions/InvalidCompositionException.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.Serialization; using Umbraco.Extensions; +using System.Text; namespace Umbraco.Cms.Core.Exceptions { @@ -86,18 +87,28 @@ public InvalidCompositionException(string contentTypeAlias, string addedComposit private static string FormatMessage(string contentTypeAlias, string addedCompositionAlias, string[] propertyTypeAliases, string[] propertyGroupAliases) { - // TODO Add property group aliases to message - return addedCompositionAlias.IsNullOrWhiteSpace() - ? string.Format( - "ContentType with alias '{0}' has an invalid composition " + - "and there was a conflict on the following PropertyTypes: '{1}'. " + - "PropertyTypes must have a unique alias across all Compositions in order to compose a valid ContentType Composition.", - contentTypeAlias, string.Join(", ", propertyTypeAliases)) - : string.Format( - "ContentType with alias '{0}' was added as a Composition to ContentType with alias '{1}', " + - "but there was a conflict on the following PropertyTypes: '{2}'. " + - "PropertyTypes must have a unique alias across all Compositions in order to compose a valid ContentType Composition.", - addedCompositionAlias, contentTypeAlias, string.Join(", ", propertyTypeAliases)); + var sb = new StringBuilder(); + + if (addedCompositionAlias.IsNullOrWhiteSpace()) + { + sb.AppendFormat("Content type with alias '{0}' has an invalid composition.", contentTypeAlias); + } + else + { + sb.AppendFormat("Content type with alias '{0}' was added as a composition to content type with alias '{1}', but there was a conflict.", addedCompositionAlias, contentTypeAlias); + } + + if (propertyTypeAliases.Length > 0) + { + sb.AppendFormat(" Property types must have a unique alias across all compositions, these aliases are duplicate: {0}.", string.Join(", ", propertyTypeAliases)); + } + + if (propertyGroupAliases.Length > 0) + { + sb.AppendFormat(" Property groups with the same alias must also have the same type across all compositions, these aliases have different types: {0}.", string.Join(", ", propertyGroupAliases)); + } + + return sb.ToString(); } /// diff --git a/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs b/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs index 8c4e57244291..197f6f6d63fd 100644 --- a/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs +++ b/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs @@ -1328,8 +1328,8 @@ private static Dictionary GetAliasesAndNames(IContentTypeService {"NodeTypeAlias", "NodeTypeAlias"}, {"CreateDate", "CreateDate"}, {"UpdateDate", "UpdateDate"}, - {"CreatorName", "CreatorName"}, - {"WriterName", "WriterName"}, + {"CreatorId", "CreatorId"}, + {"WriterId", "WriterId"}, {"Url", "Url"} }; diff --git a/src/Umbraco.Core/Extensions/PublishedModelFactoryExtensions.cs b/src/Umbraco.Core/Extensions/PublishedModelFactoryExtensions.cs index b714caf7440d..b4ffc401305d 100644 --- a/src/Umbraco.Core/Extensions/PublishedModelFactoryExtensions.cs +++ b/src/Umbraco.Core/Extensions/PublishedModelFactoryExtensions.cs @@ -12,7 +12,7 @@ namespace Umbraco.Extensions public static class PublishedModelFactoryExtensions { /// - /// Returns true if the current is an implementation of and is enabled + /// Returns true if the current is an implementation of and is enabled /// public static bool IsLiveFactoryEnabled(this IPublishedModelFactory factory) { @@ -21,8 +21,8 @@ public static bool IsLiveFactoryEnabled(this IPublishedModelFactory factory) return liveFactory.Enabled; } - // if it's not ILivePublishedModelFactory we can't determine if it's enabled or not so return true - return true; + // if it's not ILivePublishedModelFactory we know we're not using a live factory + return false; } /// diff --git a/src/Umbraco.Core/PropertyEditors/VoidEditor.cs b/src/Umbraco.Core/PropertyEditors/VoidEditor.cs index 716e722be14c..8510c982ab03 100644 --- a/src/Umbraco.Core/PropertyEditors/VoidEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/VoidEditor.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Serialization; @@ -16,8 +16,6 @@ namespace Umbraco.Cms.Core.PropertyEditors [HideFromTypeFinder] public class VoidEditor : DataEditor { - private readonly IJsonSerializer _jsonSerializer; - /// /// Initializes a new instance of the class. /// diff --git a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContent.cs b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContent.cs index 34152ebc0fca..2c79e68e1d8b 100644 --- a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContent.cs +++ b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContent.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Extensions; namespace Umbraco.Cms.Core.PublishedCache.Internal { - + // TODO: Only used in unit tests, needs to be moved to test project + [EditorBrowsable(EditorBrowsableState.Never)] public sealed class InternalPublishedContent : IPublishedContent { public InternalPublishedContent(IPublishedContentType contentType) diff --git a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContentCache.cs b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContentCache.cs index 2a197affff57..c2f8f274193b 100644 --- a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContentCache.cs +++ b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContentCache.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Xml; namespace Umbraco.Cms.Core.PublishedCache.Internal { + // TODO: Only used in unit tests, needs to be moved to test project + [EditorBrowsable(EditorBrowsableState.Never)] public sealed class InternalPublishedContentCache : PublishedCacheBase, IPublishedContentCache, IPublishedMediaCache { private readonly Dictionary _content = new Dictionary(); diff --git a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedProperty.cs b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedProperty.cs index a98eff6484f2..7fe46d8d75ca 100644 --- a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedProperty.cs +++ b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedProperty.cs @@ -1,7 +1,10 @@ -using Umbraco.Cms.Core.Models.PublishedContent; +using System.ComponentModel; +using Umbraco.Cms.Core.Models.PublishedContent; namespace Umbraco.Cms.Core.PublishedCache.Internal { + // TODO: Only used in unit tests, needs to be moved to test project + [EditorBrowsable(EditorBrowsableState.Never)] public class InternalPublishedProperty : IPublishedProperty { public IPublishedPropertyType PropertyType { get; set; } diff --git a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshot.cs b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshot.cs index c73b6cef7692..1ff8d99139ca 100644 --- a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshot.cs +++ b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshot.cs @@ -1,8 +1,12 @@ using System; +using System.ComponentModel; using Umbraco.Cms.Core.Cache; namespace Umbraco.Cms.Core.PublishedCache.Internal { + + // TODO: Only used in unit tests, needs to be moved to test project + [EditorBrowsable(EditorBrowsableState.Never)] public sealed class InternalPublishedSnapshot : IPublishedSnapshot { public InternalPublishedContentCache InnerContentCache { get; } = new InternalPublishedContentCache(); diff --git a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshotService.cs b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshotService.cs index 5dcdc5189f7c..61e2a9c2a9b5 100644 --- a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshotService.cs +++ b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshotService.cs @@ -1,10 +1,13 @@ using System.Collections.Generic; +using System.ComponentModel; using System.Threading.Tasks; using Umbraco.Cms.Core.Cache; using Umbraco.Extensions; namespace Umbraco.Cms.Core.PublishedCache.Internal { + // TODO: Only used in unit tests, needs to be moved to test project + [EditorBrowsable(EditorBrowsableState.Never)] public class InternalPublishedSnapshotService : IPublishedSnapshotService { private InternalPublishedSnapshot _snapshot; diff --git a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs index 16248854e584..ef7a29afaf55 100644 --- a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs +++ b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs @@ -1,116 +1,109 @@ using System; using System.Collections.Generic; using System.Globalization; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Routing { /// - /// Provides urls. + /// Provides urls. /// public class DefaultUrlProvider : IUrlProvider { - private readonly RequestHandlerSettings _requestSettings; + private readonly ILocalizationService _localizationService; + private readonly ILocalizedTextService _localizedTextService; private readonly ILogger _logger; + private readonly RequestHandlerSettings _requestSettings; private readonly ISiteDomainMapper _siteDomainMapper; private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly UriUtility _uriUtility; - public DefaultUrlProvider(IOptions requestSettings, ILogger logger, ISiteDomainMapper siteDomainMapper, IUmbracoContextAccessor umbracoContextAccessor, UriUtility uriUtility) + [Obsolete("Use ctor with all parameters")] + public DefaultUrlProvider(IOptions requestSettings, ILogger logger, + ISiteDomainMapper siteDomainMapper, IUmbracoContextAccessor umbracoContextAccessor, UriUtility uriUtility) + : this(requestSettings, logger, siteDomainMapper, umbracoContextAccessor, uriUtility, + StaticServiceProvider.Instance.GetRequiredService()) + { + } + + public DefaultUrlProvider( + IOptions requestSettings, + ILogger logger, + ISiteDomainMapper siteDomainMapper, + IUmbracoContextAccessor umbracoContextAccessor, + UriUtility uriUtility, + ILocalizationService localizationService) { _requestSettings = requestSettings.Value; _logger = logger; _siteDomainMapper = siteDomainMapper; - _uriUtility = uriUtility; _umbracoContextAccessor = umbracoContextAccessor; + _uriUtility = uriUtility; + _localizationService = localizationService; } - #region GetUrl - - /// - public virtual UrlInfo GetUrl(IPublishedContent content, UrlMode mode, string culture, Uri current) - { - if (!current.IsAbsoluteUri) throw new ArgumentException("Current URL must be absolute.", nameof(current)); - var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); - // will not use cache if previewing - var route = umbracoContext.Content.GetRouteById(content.Id, culture); - - return GetUrlFromRoute(route, umbracoContext, content.Id, current, mode, culture); - } - - internal UrlInfo GetUrlFromRoute(string route, IUmbracoContext umbracoContext, int id, Uri current, UrlMode mode, string culture) - { - if (string.IsNullOrWhiteSpace(route)) - { - _logger.LogDebug("Couldn't find any page with nodeId={NodeId}. This is most likely caused by the page not being published.", id); - return null; - } - - // extract domainUri and path - // route is / or / - var pos = route.IndexOf('/'); - var path = pos == 0 ? route : route.Substring(pos); - var domainUri = pos == 0 - ? null - : DomainUtilities.DomainForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainMapper, int.Parse(route.Substring(0, pos), CultureInfo.InvariantCulture), current, culture); - - // assemble the URL from domainUri (maybe null) and path - var url = AssembleUrl(domainUri, path, current, mode).ToString(); - - return UrlInfo.Url(url, culture); - } - - #endregion - #region GetOtherUrls /// - /// Gets the other URLs of a published content. + /// Gets the other URLs of a published content. /// /// The Umbraco context. /// The published content id. /// The current absolute URL. /// The other URLs for the published content. /// - /// Other URLs are those that GetUrl would not return in the current context, but would be valid - /// URLs for the node in other contexts (different domain for current request, umbracoUrlAlias...). + /// + /// Other URLs are those that GetUrl would not return in the current context, but would be valid + /// URLs for the node in other contexts (different domain for current request, umbracoUrlAlias...). + /// /// public virtual IEnumerable GetOtherUrls(int id, Uri current) { - var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); - var node = umbracoContext.Content.GetById(id); + IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); + IPublishedContent node = umbracoContext.Content.GetById(id); if (node == null) { yield break; } // look for domains, walking up the tree - var n = node; - var domainUris = DomainUtilities.DomainsForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainMapper, n.Id, current, false); + IPublishedContent n = node; + IEnumerable domainUris = + DomainUtilities.DomainsForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainMapper, n.Id, + current, false); while (domainUris == null && n != null) // n is null at root { n = n.Parent; // move to parent node - domainUris = n == null ? null : DomainUtilities.DomainsForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainMapper, n.Id, current, excludeDefault: true); + domainUris = n == null + ? null + : DomainUtilities.DomainsForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainMapper, n.Id, + current); } // no domains = exit - if (domainUris ==null) + if (domainUris == null) { yield break; } - foreach (var d in domainUris) + foreach (DomainAndUri d in domainUris) { var culture = d?.Culture; // although we are passing in culture here, if any node in this path is invariant, it ignores the culture anyways so this is ok var route = umbracoContext.Content.GetRouteById(id, culture); - if (route == null) continue; + if (route == null) + { + continue; + } // need to strip off the leading ID for the route if it exists (occurs if the route is for a node with a domain assigned) var pos = route.IndexOf('/'); @@ -124,9 +117,57 @@ public virtual IEnumerable GetOtherUrls(int id, Uri current) #endregion + #region GetUrl + + /// + public virtual UrlInfo GetUrl(IPublishedContent content, UrlMode mode, string culture, Uri current) + { + if (!current.IsAbsoluteUri) + { + throw new ArgumentException("Current URL must be absolute.", nameof(current)); + } + + IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); + // will not use cache if previewing + var route = umbracoContext.Content.GetRouteById(content.Id, culture); + + return GetUrlFromRoute(route, umbracoContext, content.Id, current, mode, culture); + } + + internal UrlInfo GetUrlFromRoute(string route, IUmbracoContext umbracoContext, int id, Uri current, + UrlMode mode, string culture) + { + if (string.IsNullOrWhiteSpace(route)) + { + _logger.LogDebug( + "Couldn't find any page with nodeId={NodeId}. This is most likely caused by the page not being published.", + id); + return null; + } + + // extract domainUri and path + // route is / or / + var pos = route.IndexOf('/'); + var path = pos == 0 ? route : route.Substring(pos); + var domainUri = pos == 0 + ? null + : DomainUtilities.DomainForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainMapper, int.Parse(route.Substring(0, pos), CultureInfo.InvariantCulture), current, culture); + + var defaultCulture = _localizationService.GetDefaultLanguageIsoCode(); + if (domainUri is not null || culture == defaultCulture || culture is null) + { + var url = AssembleUrl(domainUri, path, current, mode).ToString(); + return UrlInfo.Url(url, culture); + } + + return null; + } + + #endregion + #region Utilities - Uri AssembleUrl(DomainAndUri domainUri, string path, Uri current, UrlMode mode) + private Uri AssembleUrl(DomainAndUri domainUri, string path, Uri current, UrlMode mode) { Uri uri; @@ -135,7 +176,9 @@ Uri AssembleUrl(DomainAndUri domainUri, string path, Uri current, UrlMode mode) if (domainUri == null) // no domain was found { if (current == null) + { mode = UrlMode.Relative; // best we can do + } switch (mode) { @@ -155,10 +198,15 @@ Uri AssembleUrl(DomainAndUri domainUri, string path, Uri current, UrlMode mode) if (mode == UrlMode.Auto) { //this check is a little tricky, we can't just compare domains - if (current != null && domainUri.Uri.GetLeftPart(UriPartial.Authority) == current.GetLeftPart(UriPartial.Authority)) + if (current != null && domainUri.Uri.GetLeftPart(UriPartial.Authority) == + current.GetLeftPart(UriPartial.Authority)) + { mode = UrlMode.Relative; + } else + { mode = UrlMode.Absolute; + } } switch (mode) @@ -179,9 +227,9 @@ Uri AssembleUrl(DomainAndUri domainUri, string path, Uri current, UrlMode mode) return _uriUtility.UriFromUmbraco(uri, _requestSettings); } - string CombinePaths(string path1, string path2) + private string CombinePaths(string path1, string path2) { - string path = path1.TrimEnd(Constants.CharArrays.ForwardSlash) + path2; + var path = path1.TrimEnd(Constants.CharArrays.ForwardSlash) + path2; return path == "/" ? path : path.TrimEnd(Constants.CharArrays.ForwardSlash); } diff --git a/src/Umbraco.Core/Routing/SiteDomainMapper.cs b/src/Umbraco.Core/Routing/SiteDomainMapper.cs index d877385ef107..455889d015eb 100644 --- a/src/Umbraco.Core/Routing/SiteDomainMapper.cs +++ b/src/Umbraco.Core/Routing/SiteDomainMapper.cs @@ -4,18 +4,36 @@ using System.Text.RegularExpressions; using System.Threading; using Umbraco.Extensions; -using System.ComponentModel; namespace Umbraco.Cms.Core.Routing { /// - /// Provides utilities to handle site domains. + /// Provides utilities to handle site domains. /// public class SiteDomainMapper : ISiteDomainMapper, IDisposable { + public void Dispose() => + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(true); + + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + if (disposing) + { + // This is pretty nasty disposing a static on an instance but it's because this whole class + // is pretty fubar. I'm sure we've fixed this all up in netcore now? We need to remove all statics. + _configLock.Dispose(); + } + + _disposedValue = true; + } + } + #region Configure - private readonly ReaderWriterLockSlim _configLock = new ReaderWriterLockSlim(); + private readonly ReaderWriterLockSlim _configLock = new(); private Dictionary> _qualifiedSites; private bool _disposedValue; @@ -25,10 +43,12 @@ public class SiteDomainMapper : ISiteDomainMapper, IDisposable // these are for validation //private const string DomainValidationSource = @"^(\*|((?i:http[s]?://)?([-\w]+(\.[-\w]+)*)(:\d+)?(/[-\w]*)?))$"; private const string DomainValidationSource = @"^(((?i:http[s]?://)?([-\w]+(\.[-\w]+)*)(:\d+)?(/)?))$"; - private static readonly Regex s_domainValidation = new Regex(DomainValidationSource, RegexOptions.IgnoreCase | RegexOptions.Compiled); + + private static readonly Regex s_domainValidation = + new(DomainValidationSource, RegexOptions.IgnoreCase | RegexOptions.Compiled); /// - /// Clears the entire configuration. + /// Clears the entire configuration. /// public void Clear() { @@ -49,20 +69,21 @@ public void Clear() } } - private IEnumerable ValidateDomains(IEnumerable domains) - { + private IEnumerable ValidateDomains(IEnumerable domains) => // must use authority format w/optional scheme and port, but no path // any domain should appear only once - return domains.Select(domain => + domains.Select(domain => + { + if (!s_domainValidation.IsMatch(domain)) { - if (!s_domainValidation.IsMatch(domain)) - throw new ArgumentOutOfRangeException(nameof(domains), $"Invalid domain: \"{domain}\"."); - return domain; - }); - } + throw new ArgumentOutOfRangeException(nameof(domains), $"Invalid domain: \"{domain}\"."); + } + + return domain; + }); /// - /// Adds a site. + /// Adds a site. /// /// A key uniquely identifying the site. /// The site domains. @@ -87,7 +108,7 @@ public void AddSite(string key, IEnumerable domains) } /// - /// Adds a site. + /// Adds a site. /// /// A key uniquely identifying the site. /// The site domains. @@ -112,7 +133,7 @@ public void AddSite(string key, params string[] domains) } /// - /// Removes a site. + /// Removes a site. /// /// A key uniquely identifying the site. internal void RemoveSite(string key) @@ -122,11 +143,15 @@ internal void RemoveSite(string key) _configLock.EnterWriteLock(); if (Sites == null || !Sites.ContainsKey(key)) + { return; + } Sites.Remove(key); if (Sites.Count == 0) + { Sites = null; + } if (Bindings != null && Bindings.ContainsKey(key)) { @@ -134,11 +159,16 @@ internal void RemoveSite(string key) { Bindings[b].Remove(key); if (Bindings[b].Count == 0) + { Bindings.Remove(b); + } } + Bindings.Remove(key); if (Bindings.Count > 0) + { Bindings = null; + } } _qualifiedSites = null; @@ -153,12 +183,12 @@ internal void RemoveSite(string key) } /// - /// Binds some sites. + /// Binds some sites. /// /// The keys uniquely identifying the sites to bind. /// - /// At the moment there is no public way to unbind sites. Clear and reconfigure. - /// If site1 is bound to site2 and site2 is bound to site3 then site1 is bound to site3. + /// At the moment there is no public way to unbind sites. Clear and reconfigure. + /// If site1 is bound to site2 and site2 is bound to site3 then site1 is bound to site3. /// public void BindSites(params string[] keys) { @@ -167,7 +197,9 @@ public void BindSites(params string[] keys) _configLock.EnterWriteLock(); foreach (var key in keys.Where(key => !Sites.ContainsKey(key))) + { throw new ArgumentException($"Not an existing site key: {key}.", nameof(keys)); + } Bindings = Bindings ?? new Dictionary>(); @@ -180,9 +212,12 @@ public void BindSites(params string[] keys) foreach (var key in allkeys) { if (!Bindings.ContainsKey(key)) + { Bindings[key] = new List(); + } + var xkey = key; - var addKeys = allkeys.Where(k => k != xkey).Except(Bindings[key]); + IEnumerable addKeys = allkeys.Where(k => k != xkey).Except(Bindings[key]); Bindings[key].AddRange(addKeys); } } @@ -200,16 +235,18 @@ public void BindSites(params string[] keys) #region Map domains /// - public virtual DomainAndUri MapDomain(IReadOnlyCollection domainAndUris, Uri current, string culture, string defaultCulture) + public virtual DomainAndUri MapDomain(IReadOnlyCollection domainAndUris, Uri current, + string culture, string defaultCulture) { var currentAuthority = current.GetLeftPart(UriPartial.Authority); - var qualifiedSites = GetQualifiedSites(current); + Dictionary qualifiedSites = GetQualifiedSites(current); return MapDomain(domainAndUris, qualifiedSites, currentAuthority, culture, defaultCulture); } /// - public virtual IEnumerable MapDomains(IReadOnlyCollection domainAndUris, Uri current, bool excludeDefault, string culture, string defaultCulture) + public virtual IEnumerable MapDomains(IReadOnlyCollection domainAndUris, + Uri current, bool excludeDefault, string culture, string defaultCulture) { // TODO: ignoring cultures entirely? @@ -221,15 +258,18 @@ public virtual IEnumerable MapDomains(IReadOnlyCollection qualifiedSites = GetQualifiedSitesInsideLock(current); if (excludeDefault) { // exclude the current one (avoid producing the absolute equivalent of what GetUrl returns) - var hintWithSlash = current.EndPathWithSlash(); - var hinted = domainAndUris.FirstOrDefault(d => d.Uri.EndPathWithSlash().IsBaseOf(hintWithSlash)); + Uri hintWithSlash = current.EndPathWithSlash(); + DomainAndUri hinted = + domainAndUris.FirstOrDefault(d => d.Uri.EndPathWithSlash().IsBaseOf(hintWithSlash)); if (hinted != null) + { ret = ret.Where(d => d != hinted); + } // exclude the default one (avoid producing a possible duplicate of what GetUrl returns) // only if the default one cannot be the current one ie if hinted is not null @@ -237,17 +277,21 @@ public virtual IEnumerable MapDomains(IReadOnlyCollection d != mainDomain); } } // we do our best, but can't do the impossible if (qualifiedSites == null) + { return ret; + } // find a site that contains the current authority - var currentSite = qualifiedSites.FirstOrDefault(site => site.Value.Contains(currentAuthority)); + KeyValuePair currentSite = + qualifiedSites.FirstOrDefault(site => site.Value.Contains(currentAuthority)); // if current belongs to a site, pick every element from domainAndUris that also belong // to that site -- or to any site bound to that site @@ -257,7 +301,8 @@ public virtual IEnumerable MapDomains(IReadOnlyCollection Bindings[currentSite.Key].Contains(site.Key)); + IEnumerable> boundSites = + qualifiedSites.Where(site => Bindings[currentSite.Key].Contains(site.Key)); candidateSites = candidateSites.Union(boundSites).ToArray(); // .ToArray ensures it is evaluated before the configuration lock is exited @@ -273,7 +318,9 @@ public virtual IEnumerable MapDomains(IReadOnlyCollection + return candidateSites == null + ? ret + : ret.Where(d => { var authority = d.Uri.GetLeftPart(UriPartial.Authority); return candidateSites.Any(site => site.Value.Contains(authority)); @@ -301,11 +348,15 @@ private Dictionary GetQualifiedSitesInsideLock(Uri current) { // we do our best, but can't do the impossible if (Sites == null) + { return null; + } // cached? if (_qualifiedSites != null && _qualifiedSites.ContainsKey(current.Scheme)) + { return _qualifiedSites[current.Scheme]; + } _qualifiedSites = _qualifiedSites ?? new Dictionary>(); @@ -314,7 +365,10 @@ private Dictionary GetQualifiedSitesInsideLock(Uri current) return _qualifiedSites[current.Scheme] = Sites .ToDictionary( kvp => kvp.Key, - kvp => kvp.Value.Select(d => new Uri(UriUtilityCore.StartWithScheme(d, current.Scheme)).GetLeftPart(UriPartial.Authority)).ToArray() + kvp => kvp.Value.Select(d => + new Uri(UriUtilityCore.StartWithScheme(d, current.Scheme)) + .GetLeftPart(UriPartial.Authority)) + .ToArray() ); // .ToDictionary will evaluate and create the dictionary immediately @@ -322,61 +376,54 @@ private Dictionary GetQualifiedSitesInsideLock(Uri current) // therefore it is safe to return and exit the configuration lock } - private DomainAndUri MapDomain(IReadOnlyCollection domainAndUris, Dictionary qualifiedSites, string currentAuthority, string culture, string defaultCulture) + private DomainAndUri MapDomain(IReadOnlyCollection domainAndUris, + Dictionary qualifiedSites, string currentAuthority, string culture, string defaultCulture) { if (domainAndUris == null) + { throw new ArgumentNullException(nameof(domainAndUris)); + } + if (domainAndUris.Count == 0) + { throw new ArgumentException("Cannot be empty.", nameof(domainAndUris)); + } - // TODO: how shall we deal with cultures? - - // we do our best, but can't do the impossible - // get the "default" domain ie the first one for the culture, else the first one (exists, length > 0) if (qualifiedSites == null) { return domainAndUris.FirstOrDefault(x => x.Culture.InvariantEquals(culture)) - ?? domainAndUris.FirstOrDefault(x => x.Culture.InvariantEquals(defaultCulture)); + ?? domainAndUris.FirstOrDefault(x => x.Culture.InvariantEquals(defaultCulture)) + ?? (culture is null ? domainAndUris.First() : null); } // find a site that contains the current authority - var currentSite = qualifiedSites.FirstOrDefault(site => site.Value.Contains(currentAuthority)); + KeyValuePair currentSite = + qualifiedSites.FirstOrDefault(site => site.Value.Contains(currentAuthority)); // if current belongs to a site - try to pick the first element // from domainAndUris that also belongs to that site - var ret = currentSite.Equals(default(KeyValuePair)) + DomainAndUri ret = currentSite.Equals(default(KeyValuePair)) ? null - : domainAndUris.FirstOrDefault(d => currentSite.Value.Contains(d.Uri.GetLeftPart(UriPartial.Authority))); + : domainAndUris.FirstOrDefault(d => + currentSite.Value.Contains(d.Uri.GetLeftPart(UriPartial.Authority))); // no match means that either current does not belong to a site, or the site it belongs to - // does not contain any of domainAndUris. - return ret; - } + // does not contain any of domainAndUris. Yet we have to return something. here, it becomes + // a bit arbitrary. + // look through sites in order and pick the first domainAndUri that belongs to a site + ret = ret ?? qualifiedSites + .Where(site => site.Key != currentSite.Key) + .Select(site => domainAndUris.FirstOrDefault(domainAndUri => + site.Value.Contains(domainAndUri.Uri.GetLeftPart(UriPartial.Authority)))) + .FirstOrDefault(domainAndUri => domainAndUri != null); - #endregion + // random, really + ret = ret ?? domainAndUris.FirstOrDefault(x => x.Culture.InvariantEquals(culture)) ?? domainAndUris.First(); - protected virtual void Dispose(bool disposing) - { - if (!_disposedValue) - { - if (disposing) - { - // This is pretty nasty disposing a static on an instance but it's because this whole class - // is pretty fubar. I'm sure we've fixed this all up in netcore now? We need to remove all statics. - _configLock.Dispose(); - } - - _disposedValue = true; - } - } - - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); + return ret; } - + #endregion } } diff --git a/src/Umbraco.Core/Routing/UrlProviderExtensions.cs b/src/Umbraco.Core/Routing/UrlProviderExtensions.cs index c3e2bdee77db..3ba254112b22 100644 --- a/src/Umbraco.Core/Routing/UrlProviderExtensions.cs +++ b/src/Umbraco.Core/Routing/UrlProviderExtensions.cs @@ -15,11 +15,11 @@ namespace Umbraco.Extensions public static class UrlProviderExtensions { /// - /// Gets the URLs of the content item. + /// Gets the URLs of the content item. /// /// - /// Use when displaying URLs. If errors occur when generating the URLs, they will show in the list. - /// Contains all the URLs that we can figure out (based upon domains, etc). + /// Use when displaying URLs. If errors occur when generating the URLs, they will show in the list. + /// Contains all the URLs that we can figure out (based upon domains, etc). /// public static async Task> GetContentUrlsAsync( this IContent content, @@ -33,16 +33,55 @@ public static async Task> GetContentUrlsAsync( UriUtility uriUtility, IPublishedUrlProvider publishedUrlProvider) { - if (content == null) throw new ArgumentNullException(nameof(content)); - if (publishedRouter == null) throw new ArgumentNullException(nameof(publishedRouter)); - if (umbracoContext == null) throw new ArgumentNullException(nameof(umbracoContext)); - if (localizationService == null) throw new ArgumentNullException(nameof(localizationService)); - if (textService == null) throw new ArgumentNullException(nameof(textService)); - if (contentService == null) throw new ArgumentNullException(nameof(contentService)); - if (logger == null) throw new ArgumentNullException(nameof(logger)); - if (publishedUrlProvider == null) throw new ArgumentNullException(nameof(publishedUrlProvider)); - if (uriUtility == null) throw new ArgumentNullException(nameof(uriUtility)); - if (variationContextAccessor == null) throw new ArgumentNullException(nameof(variationContextAccessor)); + if (content == null) + { + throw new ArgumentNullException(nameof(content)); + } + + if (publishedRouter == null) + { + throw new ArgumentNullException(nameof(publishedRouter)); + } + + if (umbracoContext == null) + { + throw new ArgumentNullException(nameof(umbracoContext)); + } + + if (localizationService == null) + { + throw new ArgumentNullException(nameof(localizationService)); + } + + if (textService == null) + { + throw new ArgumentNullException(nameof(textService)); + } + + if (contentService == null) + { + throw new ArgumentNullException(nameof(contentService)); + } + + if (logger == null) + { + throw new ArgumentNullException(nameof(logger)); + } + + if (publishedUrlProvider == null) + { + throw new ArgumentNullException(nameof(publishedUrlProvider)); + } + + if (uriUtility == null) + { + throw new ArgumentNullException(nameof(uriUtility)); + } + + if (variationContextAccessor == null) + { + throw new ArgumentNullException(nameof(variationContextAccessor)); + } var result = new List(); @@ -68,7 +107,9 @@ public static async Task> GetContentUrlsAsync( // get all URLs for all cultures // in a HashSet, so de-duplicates too - foreach (UrlInfo cultureUrl in await GetContentUrlsByCultureAsync(content, cultures, publishedRouter, umbracoContext, contentService, textService, variationContextAccessor, logger, uriUtility, publishedUrlProvider)) + foreach (UrlInfo cultureUrl in await GetContentUrlsByCultureAsync(content, cultures, publishedRouter, + umbracoContext, contentService, textService, variationContextAccessor, logger, uriUtility, + publishedUrlProvider)) { urls.Add(cultureUrl); } @@ -79,15 +120,25 @@ public static async Task> GetContentUrlsAsync( // in some cases there will be the same URL for multiple cultures: // * The entire branch is invariant // * If there are less domain/cultures assigned to the branch than the number of cultures/languages installed - foreach (UrlInfo dUrl in urlGroup.DistinctBy(x => x.Text.ToUpperInvariant()).OrderBy(x => x.Text).ThenBy(x => x.Culture)) + + if (urlGroup.Key) + { + result.AddRange(urlGroup.DistinctBy(x => x.Text.ToUpperInvariant()) + .OrderBy(x => x.Text).ThenBy(x => x.Culture)); + } + else { - result.Add(dUrl); + result.AddRange(urlGroup); } + + + } // get the 'other' URLs - ie not what you'd get with GetUrl() but URLs that would route to the document, nevertheless. // for these 'other' URLs, we don't check whether they are routable, collide, anything - we just report them. - foreach (var otherUrl in publishedUrlProvider.GetOtherUrls(content.Id).OrderBy(x => x.Text).ThenBy(x => x.Culture)) + foreach (UrlInfo otherUrl in publishedUrlProvider.GetOtherUrls(content.Id).OrderBy(x => x.Text) + .ThenBy(x => x.Culture)) { // avoid duplicates if (urls.Add(otherUrl)) @@ -100,7 +151,7 @@ public static async Task> GetContentUrlsAsync( } /// - /// Tries to return a for each culture for the content while detecting collisions/errors + /// Tries to return a for each culture for the content while detecting collisions/errors /// private static async Task> GetContentUrlsByCultureAsync( IContent content, @@ -151,7 +202,8 @@ private static async Task> GetContentUrlsByCultureAsync( // got a URL, deal with collisions, add URL default: // detect collisions, etc - Attempt hasCollision = await DetectCollisionAsync(logger, content, url, culture, umbracoContext, publishedRouter, textService, variationContextAccessor, uriUtility); + Attempt hasCollision = await DetectCollisionAsync(logger, content, url, culture, + umbracoContext, publishedRouter, textService, variationContextAccessor, uriUtility); if (hasCollision) { result.Add(hasCollision.Result); @@ -168,7 +220,8 @@ private static async Task> GetContentUrlsByCultureAsync( return result; } - private static UrlInfo HandleCouldNotGetUrl(IContent content, string culture, IContentService contentService, ILocalizedTextService textService) + private static UrlInfo HandleCouldNotGetUrl(IContent content, string culture, IContentService contentService, + ILocalizedTextService textService) { // document has a published version yet its URL is "#" => a parent must be // unpublished, walk up the tree until we find it, and report. @@ -176,27 +229,31 @@ private static UrlInfo HandleCouldNotGetUrl(IContent content, string culture, IC do { parent = parent.ParentId > 0 ? contentService.GetParent(parent) : null; - } - while (parent != null && parent.Published && (!parent.ContentType.VariesByCulture() || parent.IsCulturePublished(culture))); + } while (parent != null && parent.Published && + (!parent.ContentType.VariesByCulture() || parent.IsCulturePublished(culture))); if (parent == null) { // oops, internal error return UrlInfo.Message(textService.Localize("content", "parentNotPublishedAnomaly"), culture); } - else if (!parent.Published) + + if (!parent.Published) { // totally not published - return UrlInfo.Message(textService.Localize("content", "parentNotPublished", new[] { parent.Name }), culture); - } - else - { - // culture not published - return UrlInfo.Message(textService.Localize("content", "parentCultureNotPublished", new[] {parent.Name}), culture); + return UrlInfo.Message(textService.Localize("content", "parentNotPublished", new[] { parent.Name }), + culture); } + + // culture not published + return UrlInfo.Message(textService.Localize("content", "parentCultureNotPublished", new[] { parent.Name }), + culture); } - private static async Task> DetectCollisionAsync(ILogger logger, IContent content, string url, string culture, IUmbracoContext umbracoContext, IPublishedRouter publishedRouter, ILocalizedTextService textService, IVariationContextAccessor variationContextAccessor, UriUtility uriUtility) + private static async Task> DetectCollisionAsync(ILogger logger, IContent content, string url, + string culture, IUmbracoContext umbracoContext, IPublishedRouter publishedRouter, + ILocalizedTextService textService, IVariationContextAccessor variationContextAccessor, + UriUtility uriUtility) { // test for collisions on the 'main' URL var uri = new Uri(url.TrimEnd(Constants.CharArrays.ForwardSlash), UriKind.RelativeOrAbsolute); @@ -207,11 +264,13 @@ private static async Task> DetectCollisionAsync(ILogger logger, uri = uriUtility.UriToUmbraco(uri); IPublishedRequestBuilder builder = await publishedRouter.CreateRequestAsync(uri); - IPublishedRequest pcr = await publishedRouter.RouteRequestAsync(builder, new RouteRequestOptions(RouteDirection.Outbound)); + IPublishedRequest pcr = + await publishedRouter.RouteRequestAsync(builder, new RouteRequestOptions(RouteDirection.Outbound)); if (!pcr.HasPublishedContent()) { - var logMsg = nameof(DetectCollisionAsync) + " did not resolve a content item for original url: {Url}, translated to {TranslatedUrl} and culture: {Culture}"; + var logMsg = nameof(DetectCollisionAsync) + + " did not resolve a content item for original url: {Url}, translated to {TranslatedUrl} and culture: {Culture}"; if (pcr.IgnorePublishedContentCollisions) { logger.LogDebug(logMsg, url, uri, culture); @@ -243,14 +302,7 @@ private static async Task> DetectCollisionAsync(ILogger logger, l.Reverse(); var s = "/" + string.Join("/", l) + " (id=" + pcr.PublishedContent.Id + ")"; - var urlInfo = UrlInfo.Message(textService.Localize("content", "routeError", new[] { s }), culture); - return Attempt.Succeed(urlInfo); - } - - // collisions with a different culture of the same content can never be routed. - if (!culture.InvariantEquals(pcr.Culture)) - { - var urlInfo = UrlInfo.Message(textService.Localize("content", "routeErrorCannotRoute"), culture); + var urlInfo = UrlInfo.Message(textService.Localize("content", "routeError", new[] { s }), culture); return Attempt.Succeed(urlInfo); } diff --git a/src/Umbraco.Core/Strings/DefaultUrlSegmentProvider.cs b/src/Umbraco.Core/Strings/DefaultUrlSegmentProvider.cs index a266b52f6b6f..fff22936a02f 100644 --- a/src/Umbraco.Core/Strings/DefaultUrlSegmentProvider.cs +++ b/src/Umbraco.Core/Strings/DefaultUrlSegmentProvider.cs @@ -32,7 +32,13 @@ private static string GetUrlSegmentSource(IContentBase content, string culture) if (content.HasProperty(Constants.Conventions.Content.UrlName)) source = (content.GetValue(Constants.Conventions.Content.UrlName, culture) ?? string.Empty).Trim(); if (string.IsNullOrWhiteSpace(source)) - source = content.GetCultureName(culture); + { + // If the name of a node has been updated, but it has not been published, the url should use the published name, not the current node name + // If this node has never been published (GetPublishName is null), use the unpublished name + source = (content is IContent document) && document.Edited && document.GetPublishName(culture) != null + ? document.GetPublishName(culture) + : content.GetCultureName(culture); + } return source; } } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs index 277a236e24dc..ea629e5c3afb 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs @@ -219,35 +219,32 @@ protected void DefinePlan() // so we need to ensure that migrations from 8.15 are included in the next // v9*. - Merge() - // to 8.15.0 - .To("{8DDDCD0B-D7D5-4C97-BD6A-6B38CA65752F}") - .To("{4695D0C9-0729-4976-985B-048D503665D8}") - .To("{5C424554-A32D-4852-8ED1-A13508187901}") - .With() - // to 9.0.0 RC1 - .To("{22D801BA-A1FF-4539-BFCC-2139B55594F8}") - .To("{50A43237-A6F4-49E2-A7A6-5DAD65C84669}") - .To("{3D8DADEF-0FDA-4377-A5F0-B52C2110E8F2}") - .To("{1303BDCF-2295-4645-9526-2F32E8B35ABD}") - .To("{86AC839A-0D08-4D09-B7B5-027445E255A1}") - .As("{5060F3D2-88BE-4D30-8755-CF51F28EAD12}"); - - Merge() - // to 8.17.0 - .To("{153865E9-7332-4C2A-9F9D-F20AEE078EC7}") - .With() - // This should be safe to execute again. We need it with a new name to ensure updates from all the following has executed this step. - // - 8.15.0 RC - Current state: {4695D0C9-0729-4976-985B-048D503665D8} - // - 8.15.0 Final - Current state: {5C424554-A32D-4852-8ED1-A13508187901} - // - 9.0.0 RC1 - Current state: {5060F3D2-88BE-4D30-8755-CF51F28EAD12} - .To("{622E5172-42E1-4662-AD80-9504AF5A4E53}") - .To("{10F7BB61-C550-426B-830B-7F954F689CDF}") - .To("{12DCDE7F-9AB7-4617-804F-AB66BF360980}") - .As("{5AAE6276-80DB-4ACF-B845-199BC6C37538}"); + // to 8.15.0 + To("{8DDDCD0B-D7D5-4C97-BD6A-6B38CA65752F}"); + To("{4695D0C9-0729-4976-985B-048D503665D8}"); + To("{5C424554-A32D-4852-8ED1-A13508187901}"); + + // to 8.17.0 + To("{153865E9-7332-4C2A-9F9D-F20AEE078EC7}"); + + // This should be safe to execute again. We need it with a new name to ensure updates from all the following has executed this step. + // - 8.15.0 RC - Current state: {4695D0C9-0729-4976-985B-048D503665D8} + // - 8.15.0 Final - Current state: {5C424554-A32D-4852-8ED1-A13508187901} + // - 9.0.0 RC1 - Current state: {5060F3D2-88BE-4D30-8755-CF51F28EAD12} + To("{622E5172-42E1-4662-AD80-9504AF5A4E53}"); + To("{10F7BB61-C550-426B-830B-7F954F689CDF}"); + To("{5AAE6276-80DB-4ACF-B845-199BC6C37538}"); + + // to 9.0.0 RC1 + To("{22D801BA-A1FF-4539-BFCC-2139B55594F8}"); + To("{50A43237-A6F4-49E2-A7A6-5DAD65C84669}"); + To("{3D8DADEF-0FDA-4377-A5F0-B52C2110E8F2}"); + To("{1303BDCF-2295-4645-9526-2F32E8B35ABD}"); + To("{5060F3D2-88BE-4D30-8755-CF51F28EAD12}"); + To("{A2686B49-A082-4B22-97FD-AAB154D46A57}"); // Re-run this migration to make sure it has executed to account for migrations going out of sync between versions. // TO 9.0.0-rc4 - To("5E02F241-5253-403D-B5D3-7DB00157E20F"); + To("5E02F241-5253-403D-B5D3-7DB00157E20F"); // Jaddie: This GUID is missing the { }, although this likely can't be changed now as it will break installs going forwards // TO 9.0.0 diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyHandler.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyHandler.cs index 9a7ecdbf294a..cfa1c4b3cbc0 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyHandler.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyHandler.cs @@ -122,7 +122,7 @@ private void RecursePropertyValues(IEnumerable blockData, Func _logger; private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); + private bool _disposedValue; // default ctor public PublishedContentTypeCache(IContentTypeService contentTypeService, IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService, IPublishedContentTypeFactory publishedContentTypeFactory, ILogger logger) @@ -259,8 +260,6 @@ private IPublishedContentType CreatePublishedContentType(PublishedItemType itemT private IPublishedContentType CreatePublishedContentType(PublishedItemType itemType, string alias) { - if (GetPublishedContentTypeByAlias != null) - return GetPublishedContentTypeByAlias(alias); IContentTypeComposition contentType = itemType switch { PublishedItemType.Content => _contentTypeService.Get(alias), @@ -276,8 +275,6 @@ private IPublishedContentType CreatePublishedContentType(PublishedItemType itemT private IPublishedContentType CreatePublishedContentType(PublishedItemType itemType, int id) { - if (GetPublishedContentTypeById != null) - return GetPublishedContentTypeById(id); IContentTypeComposition contentType = itemType switch { PublishedItemType.Content => _contentTypeService.Get(id), @@ -291,56 +288,6 @@ private IPublishedContentType CreatePublishedContentType(PublishedItemType itemT return _publishedContentTypeFactory.CreateContentType(contentType); } - // for unit tests - changing the callback must reset the cache obviously - // TODO: Why does this even exist? For testing you'd pass in a mocked service to get by id - private Func _getPublishedContentTypeByAlias; - internal Func GetPublishedContentTypeByAlias - { - get => _getPublishedContentTypeByAlias; - set - { - try - { - _lock.EnterWriteLock(); - - _typesByAlias.Clear(); - _typesById.Clear(); - _getPublishedContentTypeByAlias = value; - } - finally - { - if (_lock.IsWriteLockHeld) - _lock.ExitWriteLock(); - } - } - } - - // for unit tests - changing the callback must reset the cache obviously - // TODO: Why does this even exist? For testing you'd pass in a mocked service to get by id - private Func _getPublishedContentTypeById; - private bool _disposedValue; - - internal Func GetPublishedContentTypeById - { - get => _getPublishedContentTypeById; - set - { - try - { - _lock.EnterWriteLock(); - - _typesByAlias.Clear(); - _typesById.Clear(); - _getPublishedContentTypeById = value; - } - finally - { - if (_lock.IsWriteLockHeld) - _lock.ExitWriteLock(); - } - } - } - private static string GetAliasKey(PublishedItemType itemType, string alias) { string k; diff --git a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs index c1c22d0b89a2..21f95f74d62f 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs @@ -134,6 +134,9 @@ protected void ValidateLocked(TItem compositionContentType) stack.Push(c); } + var duplicatePropertyTypeAliases = new List(); + var invalidPropertyGroupAliases = new List(); + foreach (var dependency in dependencies) { if (dependency.Id == compositionContentType.Id) @@ -143,13 +146,14 @@ protected void ValidateLocked(TItem compositionContentType) if (contentTypeDependency == null) continue; - var duplicatePropertyTypeAliases = contentTypeDependency.PropertyTypes.Select(x => x.Alias).Intersect(propertyTypeAliases, StringComparer.InvariantCultureIgnoreCase).ToArray(); - var invalidPropertyGroupAliases = contentTypeDependency.PropertyGroups.Where(x => propertyGroupAliases.TryGetValue(x.Alias, out var type) && type != x.Type).Select(x => x.Alias).ToArray(); + duplicatePropertyTypeAliases.AddRange(contentTypeDependency.PropertyTypes.Select(x => x.Alias).Intersect(propertyTypeAliases, StringComparer.InvariantCultureIgnoreCase)); + invalidPropertyGroupAliases.AddRange(contentTypeDependency.PropertyGroups.Where(x => propertyGroupAliases.TryGetValue(x.Alias, out var type) && type != x.Type).Select(x => x.Alias)); + } - if (duplicatePropertyTypeAliases.Length == 0 && invalidPropertyGroupAliases.Length == 0) - continue; + if (duplicatePropertyTypeAliases.Count > 0 || invalidPropertyGroupAliases.Count > 0) - throw new InvalidCompositionException(compositionContentType.Alias, null, duplicatePropertyTypeAliases, invalidPropertyGroupAliases); + { + throw new InvalidCompositionException(compositionContentType.Alias, null, duplicatePropertyTypeAliases.Distinct().ToArray(), invalidPropertyGroupAliases.Distinct().ToArray()); } } diff --git a/src/Umbraco.PublishedCache.NuCache/ContentCache.cs b/src/Umbraco.PublishedCache.NuCache/ContentCache.cs index 875e6d2ffc05..455c31d00fa5 100644 --- a/src/Umbraco.PublishedCache.NuCache/ContentCache.cs +++ b/src/Umbraco.PublishedCache.NuCache/ContentCache.cs @@ -13,19 +13,24 @@ using Umbraco.Cms.Core.Xml.XPath; using Umbraco.Cms.Infrastructure.PublishedCache.Navigable; using Umbraco.Extensions; -using Constants = Umbraco.Cms.Core.Constants; namespace Umbraco.Cms.Infrastructure.PublishedCache { public class ContentCache : PublishedCacheBase, IPublishedContentCache, INavigableData, IDisposable { - private readonly ContentStore.Snapshot _snapshot; - private readonly IAppCache _snapshotCache; - private readonly IAppCache _elementsCache; private readonly IDomainCache _domainCache; + private readonly IAppCache _elementsCache; private readonly GlobalSettings _globalSettings; + private readonly ContentStore.Snapshot _snapshot; + private readonly IAppCache _snapshotCache; private readonly IVariationContextAccessor _variationContextAccessor; + #region IDisposable + + public void Dispose() => _snapshot.Dispose(); + + #endregion + #region Constructor // TODO: figure this out @@ -33,7 +38,9 @@ public class ContentCache : PublishedCacheBase, IPublishedContentCache, INavigab // it's too late for UmbracoContext which has captured previewDefault and stuff into these ctor vars // but, no, UmbracoContext returns snapshot.Content which comes from elements SO a resync should create a new cache - public ContentCache(bool previewDefault, ContentStore.Snapshot snapshot, IAppCache snapshotCache, IAppCache elementsCache, IDomainCache domainCache, IOptions globalSettings, IVariationContextAccessor variationContextAccessor) + public ContentCache(bool previewDefault, ContentStore.Snapshot snapshot, IAppCache snapshotCache, + IAppCache elementsCache, IDomainCache domainCache, IOptions globalSettings, + IVariationContextAccessor variationContextAccessor) : base(previewDefault) { _snapshot = snapshot; @@ -59,18 +66,23 @@ public ContentCache(bool previewDefault, ContentStore.Snapshot snapshot, IAppCac // at the moment we try our best to be backward compatible, but really, // should get rid of hideTopLevelNode and other oddities entirely, eventually - public IPublishedContent GetByRoute(string route, bool? hideTopLevelNode = null, string culture = null) - { - return GetByRoute(PreviewDefault, route, hideTopLevelNode, culture); - } + public IPublishedContent GetByRoute(string route, bool? hideTopLevelNode = null, string culture = null) => + GetByRoute(PreviewDefault, route, hideTopLevelNode, culture); - public IPublishedContent GetByRoute(bool preview, string route, bool? hideTopLevelNode = null, string culture = null) + public IPublishedContent GetByRoute(bool preview, string route, bool? hideTopLevelNode = null, + string culture = null) { - if (route == null) throw new ArgumentNullException(nameof(route)); + if (route == null) + { + throw new ArgumentNullException(nameof(route)); + } - var cache = preview == false || PublishedSnapshotService.FullCacheWhenPreviewing ? _elementsCache : _snapshotCache; + + IAppCache cache = preview == false || PublishedSnapshotService.FullCacheWhenPreviewing + ? _elementsCache + : _snapshotCache; var key = CacheKeys.ContentCacheContentByRoute(route, preview, culture); - return cache.GetCacheItem(key, () => GetByRouteInternal(preview, route, hideTopLevelNode, culture)); + return cache.GetCacheItem(key, () => GetByRouteInternal(preview, route, hideTopLevelNode, culture)); } private IPublishedContent GetByRouteInternal(bool preview, string route, bool? hideTopLevelNode, string culture) @@ -108,8 +120,10 @@ private IPublishedContent GetByRouteInternal(bool preview, string route, bool? h // hideTopLevelNode = support legacy stuff, look for /*/path/to/node // else normal, look for /path/to/node content = hideTopLevelNode.Value - ? GetAtRoot(preview).SelectMany(x => x.Children(_variationContextAccessor, culture)).FirstOrDefault(x => x.UrlSegment(_variationContextAccessor, culture) == parts[0]) - : GetAtRoot(preview).FirstOrDefault(x => x.UrlSegment(_variationContextAccessor, culture) == parts[0]); + ? GetAtRoot(preview).SelectMany(x => x.Children(_variationContextAccessor, culture)) + .FirstOrDefault(x => x.UrlSegment(_variationContextAccessor, culture) == parts[0]) + : GetAtRoot(preview) + .FirstOrDefault(x => x.UrlSegment(_variationContextAccessor, culture) == parts[0]); content = FollowRoute(content, parts, 1, culture); } @@ -118,59 +132,72 @@ private IPublishedContent GetByRouteInternal(bool preview, string route, bool? h // have to look for /foo (see note in ApplyHideTopLevelNodeFromPath). if (content == null && hideTopLevelNode.Value && parts.Length == 1) { - content = GetAtRoot(preview).FirstOrDefault(x => x.UrlSegment(_variationContextAccessor, culture) == parts[0]); + content = GetAtRoot(preview) + .FirstOrDefault(x => x.UrlSegment(_variationContextAccessor, culture) == parts[0]); } return content; } - public string GetRouteById(int contentId, string culture = null) - { - return GetRouteById(PreviewDefault, contentId, culture); - } + public string GetRouteById(int contentId, string culture = null) => + GetRouteById(PreviewDefault, contentId, culture); public string GetRouteById(bool preview, int contentId, string culture = null) { - var cache = (preview == false || PublishedSnapshotService.FullCacheWhenPreviewing) ? _elementsCache : _snapshotCache; + IAppCache cache = preview == false || PublishedSnapshotService.FullCacheWhenPreviewing + ? _elementsCache + : _snapshotCache; var key = CacheKeys.ContentCacheRouteByContent(contentId, preview, culture); - return cache.GetCacheItem(key, () => GetRouteByIdInternal(preview, contentId, null, culture)); + return cache.GetCacheItem(key, () => GetRouteByIdInternal(preview, contentId, null, culture)); } private string GetRouteByIdInternal(bool preview, int contentId, bool? hideTopLevelNode, string culture) { - var node = GetById(preview, contentId); + IPublishedContent node = GetById(preview, contentId); if (node == null) + { return null; + } hideTopLevelNode = hideTopLevelNode ?? HideTopLevelNodeFromPath; // default = settings // walk up from that node until we hit a node with a domain, // or we reach the content root, collecting URLs in the way var pathParts = new List(); - var n = node; + IPublishedContent n = node; var urlSegment = n.UrlSegment(_variationContextAccessor, culture); - var hasDomains = _domainCache.HasAssigned(n.Id); + var hasDomains = _domainCache.GetAssignedWithCulture(culture, n.Id); while (hasDomains == false && n != null) // n is null at root { // no segment indicates this is not published when this is a variant - if (urlSegment.IsNullOrWhiteSpace()) return null; + if (urlSegment.IsNullOrWhiteSpace()) + { + return null; + } pathParts.Add(urlSegment); // move to parent node n = n.Parent; if (n != null) + { urlSegment = n.UrlSegment(_variationContextAccessor, culture); + } - hasDomains = n != null && _domainCache.HasAssigned(n.Id); + hasDomains = n != null && _domainCache.GetAssignedWithCulture(culture, n.Id); } // at this point this will be the urlSegment of the root, no segment indicates this is not published when this is a variant - if (urlSegment.IsNullOrWhiteSpace()) return null; + if (urlSegment.IsNullOrWhiteSpace()) + { + return null; + } // no domain, respect HideTopLevelNodeFromPath for legacy purposes if (hasDomains == false && hideTopLevelNode.Value) + { ApplyHideTopLevelNodeFromPath(node, pathParts, preview); + } // assemble the route pathParts.Reverse(); @@ -182,7 +209,8 @@ private string GetRouteByIdInternal(bool preview, int contentId, bool? hideTopLe return route; } - private IPublishedContent FollowRoute(IPublishedContent content, IReadOnlyList parts, int start, string culture) + private IPublishedContent FollowRoute(IPublishedContent content, IReadOnlyList parts, int start, + string culture) { var i = start; while (content != null && i < parts.Count) @@ -194,6 +222,7 @@ private IPublishedContent FollowRoute(IPublishedContent content, IReadOnlyList GetAtRoot(bool preview, string cu { // handle context culture for variant if (culture == null) + { culture = _variationContextAccessor?.VariationContext?.Culture ?? ""; + } // _snapshot.GetAtRoot() returns all ContentNode at root // both .Draft and .Published cannot be null at the same time @@ -272,13 +316,15 @@ public override IEnumerable GetAtRoot(bool preview, string cu // GetNodePublishedContent may return null if !preview and there is no // published model, so we need to filter these nulls out - var atRoot = _snapshot.GetAtRoot() + IEnumerable atRoot = _snapshot.GetAtRoot() .Select(n => GetNodePublishedContent(n, preview)) .WhereNotNull(); // if a culture is specified, we must ensure that it is avail/published if (culture != "*") + { atRoot = atRoot.Where(x => x.IsInvariantOrHasCulture(culture)); + } return atRoot; } @@ -286,7 +332,9 @@ public override IEnumerable GetAtRoot(bool preview, string cu private static IPublishedContent GetNodePublishedContent(ContentNode node, bool preview) { if (node == null) + { return null; + } // both .Draft and .Published cannot be null at the same time @@ -299,7 +347,10 @@ private static IPublishedContent GetNodePublishedContent(ContentNode node, bool // this is for published content when previewing private static IPublishedContent GetPublishedContentAsDraft(IPublishedContent content /*, bool preview*/) { - if (content == null /*|| preview == false*/) return null; //content; + if (content == null /*|| preview == false*/) + { + return null; //content; + } // an object in the cache is either an IPublishedContentOrMedia, // or a model inheriting from PublishedContentExtended - in which @@ -309,12 +360,10 @@ private static IPublishedContent GetPublishedContentAsDraft(IPublishedContent co return inner.AsDraft(); } - public override bool HasContent(bool preview) - { - return preview + public override bool HasContent(bool preview) => + preview ? _snapshot.IsEmpty == false : _snapshot.GetAtRoot().Any(x => x.PublishedModel != null); - } #endregion @@ -322,21 +371,24 @@ public override bool HasContent(bool preview) public override IPublishedContent GetSingleByXPath(bool preview, string xpath, XPathVariable[] vars) { - var navigator = CreateNavigator(preview); - var iterator = navigator.Select(xpath, vars); + XPathNavigator navigator = CreateNavigator(preview); + XPathNodeIterator iterator = navigator.Select(xpath, vars); return GetSingleByXPath(iterator); } public override IPublishedContent GetSingleByXPath(bool preview, XPathExpression xpath, XPathVariable[] vars) { - var navigator = CreateNavigator(preview); - var iterator = navigator.Select(xpath, vars); + XPathNavigator navigator = CreateNavigator(preview); + XPathNodeIterator iterator = navigator.Select(xpath, vars); return GetSingleByXPath(iterator); } private static IPublishedContent GetSingleByXPath(XPathNodeIterator iterator) { - if (iterator.MoveNext() == false) return null; + if (iterator.MoveNext() == false) + { + return null; + } var xnav = iterator.Current as NavigableNavigator; var xcontent = xnav?.UnderlyingObject as NavigableContent; @@ -345,15 +397,16 @@ private static IPublishedContent GetSingleByXPath(XPathNodeIterator iterator) public override IEnumerable GetByXPath(bool preview, string xpath, XPathVariable[] vars) { - var navigator = CreateNavigator(preview); - var iterator = navigator.Select(xpath, vars); + XPathNavigator navigator = CreateNavigator(preview); + XPathNodeIterator iterator = navigator.Select(xpath, vars); return GetByXPath(iterator); } - public override IEnumerable GetByXPath(bool preview, XPathExpression xpath, XPathVariable[] vars) + public override IEnumerable GetByXPath(bool preview, XPathExpression xpath, + XPathVariable[] vars) { - var navigator = CreateNavigator(preview); - var iterator = navigator.Select(xpath, vars); + XPathNavigator navigator = CreateNavigator(preview); + XPathNodeIterator iterator = navigator.Select(xpath, vars); return GetByXPath(iterator); } @@ -364,7 +417,10 @@ private static IEnumerable GetByXPath(XPathNodeIterator itera { var xnav = iterator.Current as NavigableNavigator; var xcontent = xnav?.UnderlyingObject as NavigableContent; - if (xcontent == null) continue; + if (xcontent == null) + { + continue; + } yield return xcontent.InnerContent; } @@ -395,14 +451,5 @@ public override XPathNavigator CreateNodeNavigator(int id, bool preview) public override IPublishedContentType GetContentType(Guid key) => _snapshot.GetContentType(key); #endregion - - #region IDisposable - - public void Dispose() - { - _snapshot.Dispose(); - } - - #endregion } } diff --git a/src/Umbraco.PublishedCache.NuCache/ContentNode.cs b/src/Umbraco.PublishedCache.NuCache/ContentNode.cs index 23088df3adc6..beb598686163 100644 --- a/src/Umbraco.PublishedCache.NuCache/ContentNode.cs +++ b/src/Umbraco.PublishedCache.NuCache/ContentNode.cs @@ -175,13 +175,6 @@ private IPublishedContent GetModel(ref IPublishedContent model, ContentData cont public IPublishedContent PublishedModel => GetModel(ref _publishedModel, _publishedData); public ContentNodeKit ToKit() - => new ContentNodeKit - { - Node = this, - ContentTypeId = ContentType.Id, - - DraftData = _draftData, - PublishedData = _publishedData - }; + => new ContentNodeKit(this, ContentType.Id, _draftData, _publishedData); } } diff --git a/src/Umbraco.PublishedCache.NuCache/ContentNodeKit.cs b/src/Umbraco.PublishedCache.NuCache/ContentNodeKit.cs index bb05e1470661..3f230925fe34 100644 --- a/src/Umbraco.PublishedCache.NuCache/ContentNodeKit.cs +++ b/src/Umbraco.PublishedCache.NuCache/ContentNodeKit.cs @@ -1,23 +1,39 @@ -using Umbraco.Cms.Core.Models.PublishedContent; +using System; +using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; namespace Umbraco.Cms.Infrastructure.PublishedCache { - // what's needed to actually build a content node public struct ContentNodeKit { + [Obsolete("This will be changed to a property in future versions")] public ContentNode Node; + + [Obsolete("This will be changed to a property in future versions")] public int ContentTypeId; + + [Obsolete("This will be changed to a property in future versions")] public ContentData DraftData; + + [Obsolete("This will be changed to a property in future versions")] public ContentData PublishedData; + public ContentNodeKit(ContentNode node, int contentTypeId, ContentData draftData, ContentData publishedData) + { + Node = node; + ContentTypeId = contentTypeId; + DraftData = draftData; + PublishedData = publishedData; + } + + public bool IsEmpty => Node == null; public bool IsNull => ContentTypeId < 0; public static ContentNodeKit Empty { get; } = new ContentNodeKit(); - public static ContentNodeKit Null { get; } = new ContentNodeKit { ContentTypeId = -1 }; + public static ContentNodeKit Null { get; } = new ContentNodeKit(null, -1, null, null); public void Build( IPublishedContentType contentType, @@ -41,12 +57,9 @@ public void Build( } public ContentNodeKit Clone(IPublishedModelFactory publishedModelFactory) - => new ContentNodeKit - { - ContentTypeId = ContentTypeId, - DraftData = DraftData, - PublishedData = PublishedData, - Node = new ContentNode(Node, publishedModelFactory) - }; + => new ContentNodeKit(new ContentNode(Node, publishedModelFactory), ContentTypeId, DraftData, PublishedData); + + public ContentNodeKit Clone(IPublishedModelFactory publishedModelFactory, ContentData draftData, ContentData publishedData) + => new ContentNodeKit(new ContentNode(Node, publishedModelFactory), ContentTypeId, draftData, publishedData); } } diff --git a/src/Umbraco.PublishedCache.NuCache/ContentStore.cs b/src/Umbraco.PublishedCache.NuCache/ContentStore.cs index 6e6d6e33aa22..240e6c8861a6 100644 --- a/src/Umbraco.PublishedCache.NuCache/ContentStore.cs +++ b/src/Umbraco.PublishedCache.NuCache/ContentStore.cs @@ -104,7 +104,11 @@ public ContentStore( private class WriteLockInfo { +#pragma warning disable IDE1006 // Naming Styles + + // This is a field that is used for ref operations public bool Taken; +#pragma warning restore IDE1006 // Naming Styles } // a scope contextual that represents a locked writer to the dictionary diff --git a/src/Umbraco.PublishedCache.NuCache/DataSource/BTree.ContentDataSerializer.cs b/src/Umbraco.PublishedCache.NuCache/DataSource/BTree.ContentDataSerializer.cs index 99ce9365fcf6..ad093f229241 100644 --- a/src/Umbraco.PublishedCache.NuCache/DataSource/BTree.ContentDataSerializer.cs +++ b/src/Umbraco.PublishedCache.NuCache/DataSource/BTree.ContentDataSerializer.cs @@ -13,27 +13,25 @@ public ContentDataSerializer(IDictionaryOfPropertyDataSerializer dictionaryOfPro _dictionaryOfPropertyDataSerializer = dictionaryOfPropertyDataSerializer; if(_dictionaryOfPropertyDataSerializer == null) { - _dictionaryOfPropertyDataSerializer = DefaultPropertiesSerializer; + _dictionaryOfPropertyDataSerializer = s_defaultPropertiesSerializer; } } - private static readonly DictionaryOfPropertyDataSerializer DefaultPropertiesSerializer = new DictionaryOfPropertyDataSerializer(); - private static readonly DictionaryOfCultureVariationSerializer DefaultCultureVariationsSerializer = new DictionaryOfCultureVariationSerializer(); + private static readonly DictionaryOfPropertyDataSerializer s_defaultPropertiesSerializer = new DictionaryOfPropertyDataSerializer(); + private static readonly DictionaryOfCultureVariationSerializer s_defaultCultureVariationsSerializer = new DictionaryOfCultureVariationSerializer(); private readonly IDictionaryOfPropertyDataSerializer _dictionaryOfPropertyDataSerializer; public ContentData ReadFrom(Stream stream) { - return new ContentData - { - Published = PrimitiveSerializer.Boolean.ReadFrom(stream), - Name = PrimitiveSerializer.String.ReadFrom(stream), - UrlSegment = PrimitiveSerializer.String.ReadFrom(stream), - VersionId = PrimitiveSerializer.Int32.ReadFrom(stream), - VersionDate = PrimitiveSerializer.DateTime.ReadFrom(stream), - WriterId = PrimitiveSerializer.Int32.ReadFrom(stream), - TemplateId = PrimitiveSerializer.Int32.ReadFrom(stream), - Properties = _dictionaryOfPropertyDataSerializer.ReadFrom(stream), // TODO: We don't want to allocate empty arrays - CultureInfos = DefaultCultureVariationsSerializer.ReadFrom(stream) // TODO: We don't want to allocate empty arrays - }; + var published = PrimitiveSerializer.Boolean.ReadFrom(stream); + var name = PrimitiveSerializer.String.ReadFrom(stream); + var urlSegment = PrimitiveSerializer.String.ReadFrom(stream); + var versionId = PrimitiveSerializer.Int32.ReadFrom(stream); + var versionDate = PrimitiveSerializer.DateTime.ReadFrom(stream); + var writerId = PrimitiveSerializer.Int32.ReadFrom(stream); + var templateId = PrimitiveSerializer.Int32.ReadFrom(stream); + var properties = _dictionaryOfPropertyDataSerializer.ReadFrom(stream); // TODO: We don't want to allocate empty arrays + var cultureInfos = s_defaultCultureVariationsSerializer.ReadFrom(stream); // TODO: We don't want to allocate empty arrays + return new ContentData(name, urlSegment, versionId, versionDate, writerId, templateId, published, properties, cultureInfos); } public void WriteTo(ContentData value, Stream stream) @@ -49,7 +47,7 @@ public void WriteTo(ContentData value, Stream stream) PrimitiveSerializer.Int32.WriteTo(value.TemplateId.Value, stream); } _dictionaryOfPropertyDataSerializer.WriteTo(value.Properties, stream); - DefaultCultureVariationsSerializer.WriteTo(value.CultureInfos, stream); + s_defaultCultureVariationsSerializer.WriteTo(value.CultureInfos, stream); } } } diff --git a/src/Umbraco.PublishedCache.NuCache/DataSource/BTree.ContentNodeKitSerializer.cs b/src/Umbraco.PublishedCache.NuCache/DataSource/BTree.ContentNodeKitSerializer.cs index db0886ce792a..42da3e601ba0 100644 --- a/src/Umbraco.PublishedCache.NuCache/DataSource/BTree.ContentNodeKitSerializer.cs +++ b/src/Umbraco.PublishedCache.NuCache/DataSource/BTree.ContentNodeKitSerializer.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using CSharpTest.Net.Serialization; namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource @@ -10,19 +10,17 @@ public ContentNodeKitSerializer(ContentDataSerializer contentDataSerializer = nu _contentDataSerializer = contentDataSerializer; if(_contentDataSerializer == null) { - _contentDataSerializer = DefaultDataSerializer; + _contentDataSerializer = s_defaultDataSerializer; } } - static readonly ContentDataSerializer DefaultDataSerializer = new ContentDataSerializer(); + static readonly ContentDataSerializer s_defaultDataSerializer = new ContentDataSerializer(); private readonly ContentDataSerializer _contentDataSerializer; //static readonly ListOfIntSerializer ChildContentIdsSerializer = new ListOfIntSerializer(); public ContentNodeKit ReadFrom(Stream stream) { - var kit = new ContentNodeKit - { - Node = new ContentNode( + var contentNode = new ContentNode( PrimitiveSerializer.Int32.ReadFrom(stream), // id PrimitiveSerializer.Guid.ReadFrom(stream), // uid PrimitiveSerializer.Int32.ReadFrom(stream), // level @@ -31,15 +29,27 @@ public ContentNodeKit ReadFrom(Stream stream) PrimitiveSerializer.Int32.ReadFrom(stream), // parent id PrimitiveSerializer.DateTime.ReadFrom(stream), // date created PrimitiveSerializer.Int32.ReadFrom(stream) // creator id - ), - ContentTypeId = PrimitiveSerializer.Int32.ReadFrom(stream) - }; + ); + + int contentTypeId = PrimitiveSerializer.Int32.ReadFrom(stream); var hasDraft = PrimitiveSerializer.Boolean.ReadFrom(stream); + ContentData draftData = null; + ContentData publishedData = null; if (hasDraft) - kit.DraftData = _contentDataSerializer.ReadFrom(stream); + { + draftData = _contentDataSerializer.ReadFrom(stream); + } var hasPublished = PrimitiveSerializer.Boolean.ReadFrom(stream); if (hasPublished) - kit.PublishedData = _contentDataSerializer.ReadFrom(stream); + { + publishedData = _contentDataSerializer.ReadFrom(stream); + } + var kit = new ContentNodeKit( + contentNode, + contentTypeId, + draftData, + publishedData); + return kit; } diff --git a/src/Umbraco.PublishedCache.NuCache/DataSource/ContentData.cs b/src/Umbraco.PublishedCache.NuCache/DataSource/ContentData.cs index a4fd45546899..a461cda437ee 100644 --- a/src/Umbraco.PublishedCache.NuCache/DataSource/ContentData.cs +++ b/src/Umbraco.PublishedCache.NuCache/DataSource/ContentData.cs @@ -8,19 +8,38 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource /// public class ContentData { - public string Name { get; set; } - public string UrlSegment { get; set; } - public int VersionId { get; set; } - public DateTime VersionDate { get; set; } - public int WriterId { get; set; } - public int? TemplateId { get; set; } - public bool Published { get; set; } + [Obsolete("Use ctor with all params, as the pros should be immutable")] + public ContentData() + { - public IDictionary Properties { get; set; } + } + + public ContentData(string name, string urlSegment, int versionId, DateTime versionDate, int writerId, int? templateId, bool published, IDictionary properties, IReadOnlyDictionary cultureInfos) + { + Name = name ?? throw new ArgumentNullException(nameof(name)); + UrlSegment = urlSegment; + VersionId = versionId; + VersionDate = versionDate; + WriterId = writerId; + TemplateId = templateId; + Published = published; + Properties = properties ?? throw new ArgumentNullException(nameof(properties)); + CultureInfos = cultureInfos; + } + + public string Name { get; [Obsolete("Do not change this, use ctor with params and have this object immutable.")] set; } + public string UrlSegment { get; [Obsolete("Do not change this, use ctor with params and have this object immutable.")] set; } + public int VersionId { get; [Obsolete("Do not change this, use ctor with params and have this object immutable.")] set; } + public DateTime VersionDate { get; [Obsolete("Do not change this, use ctor with params and have this object immutable.")] set; } + public int WriterId { get; [Obsolete("Do not change this, use ctor with params and have this object immutable.")] set; } + public int? TemplateId { get; [Obsolete("Do not change this, use ctor with params and have this object immutable.")] set; } + public bool Published { get; [Obsolete("Do not change this, use ctor with params and have this object immutable.")] set; } + + public IDictionary Properties { get; [Obsolete("Do not change this, use ctor with params and have this object immutable.")] set; } /// /// The collection of language Id to name for the content item /// - public IReadOnlyDictionary CultureInfos { get; set; } + public IReadOnlyDictionary CultureInfos { get; [Obsolete("Do not change this, use ctor with params and have this object immutable.")] set; } } } diff --git a/src/Umbraco.PublishedCache.NuCache/DomainCacheExtensions.cs b/src/Umbraco.PublishedCache.NuCache/DomainCacheExtensions.cs new file mode 100644 index 000000000000..61f10917fd3c --- /dev/null +++ b/src/Umbraco.PublishedCache.NuCache/DomainCacheExtensions.cs @@ -0,0 +1,15 @@ +using System.Linq; +using Umbraco.Cms.Core.PublishedCache; + +namespace Umbraco.Cms.Infrastructure.PublishedCache +{ + public static class DomainCacheExtensions + { + public static bool GetAssignedWithCulture(this IDomainCache domainCache, string culture, int documentId, bool includeWildcards = false) + { + var assigned = domainCache.GetAssigned(documentId, includeWildcards); + + return culture is null ? assigned.Any() : assigned.Any(x => x.Culture == culture); + } + } +} diff --git a/src/Umbraco.PublishedCache.NuCache/Persistence/NuCacheContentRepository.cs b/src/Umbraco.PublishedCache.NuCache/Persistence/NuCacheContentRepository.cs index 2919edb8c345..649bc0eebbe6 100644 --- a/src/Umbraco.PublishedCache.NuCache/Persistence/NuCacheContentRepository.cs +++ b/src/Umbraco.PublishedCache.NuCache/Persistence/NuCacheContentRepository.cs @@ -820,18 +820,16 @@ private ContentNodeKit CreateContentNodeKit(ContentSourceDto dto, IContentCacheD bool published = false; var deserializedContent = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw, published); - d = new ContentData - { - Name = dto.EditName, - Published = published, - TemplateId = dto.EditTemplateId, - VersionId = dto.VersionId, - VersionDate = dto.EditVersionDate, - WriterId = dto.EditWriterId, - Properties = deserializedContent.PropertyData, // TODO: We don't want to allocate empty arrays - CultureInfos = deserializedContent.CultureData, - UrlSegment = deserializedContent.UrlSegment - }; + d = new ContentData( + dto.EditName, + deserializedContent.UrlSegment, + dto.VersionId, + dto.EditVersionDate, + dto.EditWriterId, + dto.EditTemplateId, + published, + deserializedContent.PropertyData, + deserializedContent.CultureData); } } @@ -851,31 +849,23 @@ private ContentNodeKit CreateContentNodeKit(ContentSourceDto dto, IContentCacheD bool published = true; var deserializedContent = serializer.Deserialize(dto, dto.PubData, dto.PubDataRaw, published); - p = new ContentData - { - Name = dto.PubName, - UrlSegment = deserializedContent.UrlSegment, - Published = published, - TemplateId = dto.PubTemplateId, - VersionId = dto.VersionId, - VersionDate = dto.PubVersionDate, - WriterId = dto.PubWriterId, - Properties = deserializedContent.PropertyData, // TODO: We don't want to allocate empty arrays - CultureInfos = deserializedContent.CultureData - }; + p = new ContentData( + dto.PubName, + deserializedContent.UrlSegment, + dto.VersionId, + dto.PubVersionDate, + dto.PubWriterId, + dto.PubTemplateId, + published, + deserializedContent.PropertyData, + deserializedContent.CultureData); } } var n = new ContentNode(dto.Id, dto.Key, dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId); - var s = new ContentNodeKit - { - Node = n, - ContentTypeId = dto.ContentTypeId, - DraftData = d, - PublishedData = p - }; + var s = new ContentNodeKit(n, dto.ContentTypeId, d, p); return s; } @@ -888,27 +878,21 @@ private ContentNodeKit CreateMediaNodeKit(ContentSourceDto dto, IContentCacheDat bool published = true; var deserializedMedia = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw, published); - var p = new ContentData - { - Name = dto.EditName, - Published = published, - TemplateId = -1, - VersionId = dto.VersionId, - VersionDate = dto.EditVersionDate, - WriterId = dto.CreatorId, // what-else? - Properties = deserializedMedia.PropertyData, // TODO: We don't want to allocate empty arrays - CultureInfos = deserializedMedia.CultureData - }; + var p = new ContentData( + dto.EditName, + null, + dto.VersionId, + dto.EditVersionDate, + dto.CreatorId, + -1, + published, + deserializedMedia.PropertyData, + deserializedMedia.CultureData); var n = new ContentNode(dto.Id, dto.Key, dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId); - var s = new ContentNodeKit - { - Node = n, - ContentTypeId = dto.ContentTypeId, - PublishedData = p - }; + var s = new ContentNodeKit(n, dto.ContentTypeId, null, p); return s; } diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedMember.cs b/src/Umbraco.PublishedCache.NuCache/PublishedMember.cs index 4796f3229534..53cc597cf5b1 100644 --- a/src/Umbraco.PublishedCache.NuCache/PublishedMember.cs +++ b/src/Umbraco.PublishedCache.NuCache/PublishedMember.cs @@ -34,15 +34,8 @@ public static IPublishedContent Create( IVariationContextAccessor variationContextAccessor, IPublishedModelFactory publishedModelFactory) { - var d = new ContentData - { - Name = member.Name, - Published = previewing, - TemplateId = -1, - VersionDate = member.UpdateDate, - WriterId = member.CreatorId, // what else? - Properties = GetPropertyValues(contentType, member) - }; + var d = new ContentData(member.Name, null, 0, member.UpdateDate, member.CreatorId, -1, previewing, GetPropertyValues(contentType, member), null); + var n = new ContentNode( member.Id, member.Key, diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs index 83d2bd5ccbfe..20df72608076 100644 --- a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs @@ -46,7 +46,6 @@ internal class PublishedSnapshotService : IPublishedSnapshotService private readonly IPublishedModelFactory _publishedModelFactory; private readonly IDefaultCultureAccessor _defaultCultureAccessor; private readonly IHostingEnvironment _hostingEnvironment; - private readonly IContentCacheDataSerializerFactory _contentCacheDataSerializerFactory; private readonly ContentDataSerializer _contentDataSerializer; private readonly NuCacheSettings _config; @@ -93,7 +92,6 @@ public PublishedSnapshotService( IPublishedModelFactory publishedModelFactory, IHostingEnvironment hostingEnvironment, IOptions config, - IContentCacheDataSerializerFactory contentCacheDataSerializerFactory, ContentDataSerializer contentDataSerializer) { _options = options; @@ -111,7 +109,6 @@ public PublishedSnapshotService( _defaultCultureAccessor = defaultCultureAccessor; _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; - _contentCacheDataSerializerFactory = contentCacheDataSerializerFactory; _contentDataSerializer = contentDataSerializer; _config = config.Value; _publishedModelFactory = publishedModelFactory; diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentTypeControllerBase.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentTypeControllerBase.cs index acfac62741b7..0190d5d40074 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentTypeControllerBase.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentTypeControllerBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Net.Mime; using System.Text; @@ -16,12 +17,11 @@ using Umbraco.Cms.Web.BackOffice.Filters; using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Extensions; -using Constants = Umbraco.Cms.Core.Constants; namespace Umbraco.Cms.Web.BackOffice.Controllers { /// - /// Am abstract API controller providing functionality used for dealing with content and media types + /// Am abstract API controller providing functionality used for dealing with content and media types /// [PluginController(Constants.Web.Mvc.BackOfficeApiArea)] [PrefixlessBodyModelValidator] @@ -39,13 +39,15 @@ protected ContentTypeControllerBase( IUmbracoMapper umbracoMapper, ILocalizedTextService localizedTextService) { - _editorValidatorCollection = editorValidatorCollection ?? throw new ArgumentNullException(nameof(editorValidatorCollection)); + _editorValidatorCollection = editorValidatorCollection ?? + throw new ArgumentNullException(nameof(editorValidatorCollection)); CultureDictionary = cultureDictionary ?? throw new ArgumentNullException(nameof(cultureDictionary)); ContentTypeService = contentTypeService ?? throw new ArgumentNullException(nameof(contentTypeService)); MediaTypeService = mediaTypeService ?? throw new ArgumentNullException(nameof(mediaTypeService)); MemberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); UmbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); - LocalizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); + LocalizedTextService = + localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); } protected ICultureDictionary CultureDictionary { get; } @@ -56,22 +58,26 @@ protected ContentTypeControllerBase( public ILocalizedTextService LocalizedTextService { get; } /// - /// Returns the available composite content types for a given content type + /// Returns the available composite content types for a given content type /// /// /// - /// This is normally an empty list but if additional content type aliases are passed in, any content types containing those aliases will be filtered out - /// along with any content types that have matching property types that are included in the filtered content types + /// This is normally an empty list but if additional content type aliases are passed in, any content types containing + /// those aliases will be filtered out + /// along with any content types that have matching property types that are included in the filtered content types /// /// - /// This is normally an empty list but if additional property type aliases are passed in, any content types that have these aliases will be filtered out. - /// This is required because in the case of creating/modifying a content type because new property types being added to it are not yet persisted so cannot - /// be looked up via the db, they need to be passed in. + /// This is normally an empty list but if additional property type aliases are passed in, any content types that have + /// these aliases will be filtered out. + /// This is required because in the case of creating/modifying a content type because new property types being added to + /// it are not yet persisted so cannot + /// be looked up via the db, they need to be passed in. /// /// /// Whether the composite content types should be applicable for an element type /// - protected ActionResult>> PerformGetAvailableCompositeContentTypes(int contentTypeId, + protected ActionResult>> PerformGetAvailableCompositeContentTypes( + int contentTypeId, UmbracoObjectTypes type, string[] filterContentTypes, string[] filterPropertyTypes, @@ -89,26 +95,38 @@ protected ActionResult>> PerformGetAvailabl if (contentTypeId > 0) { source = ContentTypeService.Get(contentTypeId); - if (source == null) return NotFound(); + if (source == null) + { + return NotFound(); + } } + allContentTypes = ContentTypeService.GetAll().Cast().ToArray(); break; case UmbracoObjectTypes.MediaType: if (contentTypeId > 0) { - source =MediaTypeService.Get(contentTypeId); - if (source == null) return NotFound(); + source = MediaTypeService.Get(contentTypeId); + if (source == null) + { + return NotFound(); + } } - allContentTypes =MediaTypeService.GetAll().Cast().ToArray(); + + allContentTypes = MediaTypeService.GetAll().Cast().ToArray(); break; case UmbracoObjectTypes.MemberType: if (contentTypeId > 0) { source = MemberTypeService.Get(contentTypeId); - if (source == null) return NotFound(); + if (source == null) + { + return NotFound(); + } } + allContentTypes = MemberTypeService.GetAll().Cast().ToArray(); break; @@ -116,16 +134,20 @@ protected ActionResult>> PerformGetAvailabl throw new ArgumentOutOfRangeException("The entity type was not a content type"); } - var availableCompositions = ContentTypeService.GetAvailableCompositeContentTypes(source, allContentTypes, filterContentTypes, filterPropertyTypes, isElement); + ContentTypeAvailableCompositionsResults availableCompositions = + ContentTypeService.GetAvailableCompositeContentTypes(source, allContentTypes, filterContentTypes, + filterPropertyTypes, isElement); - - var currCompositions = source == null ? new IContentTypeComposition[] { } : source.ContentTypeComposition.ToArray(); + IContentTypeComposition[] currCompositions = + source == null ? new IContentTypeComposition[] { } : source.ContentTypeComposition.ToArray(); var compAliases = currCompositions.Select(x => x.Alias).ToArray(); - var ancestors = availableCompositions.Ancestors.Select(x => x.Alias); + IEnumerable ancestors = availableCompositions.Ancestors.Select(x => x.Alias); return availableCompositions.Results - .Select(x => new Tuple(UmbracoMapper.Map(x.Composition), x.Allowed)) + .Select(x => + new Tuple(UmbracoMapper.Map(x.Composition), + x.Allowed)) .Select(x => { //we need to ensure that the item is enabled if it is already selected @@ -139,9 +161,10 @@ protected ActionResult>> PerformGetAvailabl //translate the name x.Item1.Name = TranslateItem(x.Item1.Name); - var contentType = allContentTypes.FirstOrDefault(c => c.Key == x.Item1.Key); - var containers = GetEntityContainers(contentType, type)?.ToArray(); - var containerPath = $"/{(containers != null && containers.Any() ? $"{string.Join("/", containers.Select(c => c.Name))}/" : null)}"; + IContentTypeComposition contentType = allContentTypes.FirstOrDefault(c => c.Key == x.Item1.Key); + EntityContainer[] containers = GetEntityContainers(contentType, type)?.ToArray(); + var containerPath = + $"/{(containers != null && containers.Any() ? $"{string.Join("/", containers.Select(c => c.Name))}/" : null)}"; x.Item1.AdditionalData["containerPath"] = containerPath; return x; @@ -149,7 +172,8 @@ protected ActionResult>> PerformGetAvailabl .ToList(); } - private IEnumerable GetEntityContainers(IContentTypeComposition contentType, UmbracoObjectTypes type) + private IEnumerable GetEntityContainers(IContentTypeComposition contentType, + UmbracoObjectTypes type) { if (contentType == null) { @@ -170,12 +194,13 @@ private IEnumerable GetEntityContainers(IContentTypeComposition } /// - /// Returns a list of content types where a particular composition content type is used + /// Returns a list of content types where a particular composition content type is used /// /// Type of content Type, eg documentType or mediaType /// Id of composition content type /// - protected ActionResult> PerformGetWhereCompositionIsUsedInContentTypes(int contentTypeId, UmbracoObjectTypes type) + protected ActionResult> PerformGetWhereCompositionIsUsedInContentTypes( + int contentTypeId, UmbracoObjectTypes type) { var id = 0; @@ -190,7 +215,7 @@ protected ActionResult> PerformGetWhereCompositionIsUse break; case UmbracoObjectTypes.MediaType: - source =MediaTypeService.Get(contentTypeId); + source = MediaTypeService.Get(contentTypeId); break; case UmbracoObjectTypes.MemberType: @@ -202,7 +227,9 @@ protected ActionResult> PerformGetWhereCompositionIsUse } if (source == null) + { return NotFound(); + } id = source.Id; } @@ -216,7 +243,7 @@ protected ActionResult> PerformGetWhereCompositionIsUse break; case UmbracoObjectTypes.MediaType: - composedOf =MediaTypeService.GetComposedOf(id); + composedOf = MediaTypeService.GetComposedOf(id); break; case UmbracoObjectTypes.MemberType: @@ -242,10 +269,14 @@ EntityBasic TranslateName(EntityBasic e) protected string TranslateItem(string text) { if (text == null) + { return null; + } if (text.StartsWith("#") == false) + { return text; + } text = text.Substring(1); return CultureDictionary[text].IfNullOrWhiteSpace(text); @@ -261,18 +292,22 @@ protected ActionResult PerformPostSave 0 ? getContentType(ctId) : null; - if (ctId > 0 && ct == null) return NotFound(); + TContentType ct = ctId > 0 ? getContentType(ctId) : null; + if (ctId > 0 && ct == null) + { + return NotFound(); + } //Validate that there's no other ct with the same alias // it in fact cannot be the same as any content type alias (member, content or media) because // this would interfere with how ModelsBuilder works and also how many of the published caches // works since that is based on aliases. - var allAliases = ContentTypeService.GetAllContentTypeAliases(); + IEnumerable allAliases = ContentTypeService.GetAllContentTypeAliases(); var exists = allAliases.InvariantContains(contentTypeSave.Alias); if (exists && (ctId == 0 || !ct.Alias.InvariantEquals(contentTypeSave.Alias))) { - ModelState.AddModelError("Alias", LocalizedTextService.Localize("editcontenttype", "aliasAlreadyExists")); + ModelState.AddModelError("Alias", + LocalizedTextService.Localize("editcontenttype", "aliasAlreadyExists")); } // execute the external validators @@ -280,13 +315,14 @@ protected ActionResult PerformPostSave(ctId, contentTypeSave, ct); + TContentTypeDisplay err = + CreateModelStateValidationEror(ctId, contentTypeSave, ct); return ValidationProblem(err); } //filter out empty properties contentTypeSave.Groups = contentTypeSave.Groups.Where(x => x.Name.IsNullOrWhiteSpace() == false).ToList(); - foreach (var group in contentTypeSave.Groups) + foreach (PropertyGroupBasic group in contentTypeSave.Groups) { group.Properties = group.Properties.Where(x => x.Alias.IsNullOrWhiteSpace() == false).ToList(); } @@ -302,12 +338,22 @@ protected ActionResult PerformPostSave(ex, contentTypeSave, ct, ctId); - if (responseEx != null) return ValidationProblem(responseEx); + TContentTypeDisplay responseEx = + CreateInvalidCompositionResponseException( + ex, contentTypeSave, ct, ctId); + if (responseEx != null) + { + return ValidationProblem(responseEx); + } } - var exResult = CreateCompositionValidationExceptionIfInvalid(contentTypeSave, ct); - if (exResult != null) return ValidationProblem(exResult); + TContentTypeDisplay exResult = + CreateCompositionValidationExceptionIfInvalid( + contentTypeSave, ct); + if (exResult != null) + { + return ValidationProblem(exResult); + } saveContentType(ct); @@ -329,7 +375,8 @@ protected ActionResult PerformPostSave x == 0); - contentTypeSave.AllowedContentTypes = contentTypeSave.AllowedContentTypes.Where(x => x > 0).ToList(); + contentTypeSave.AllowedContentTypes = + contentTypeSave.AllowedContentTypes.Where(x => x > 0).ToList(); } //save as new @@ -342,15 +389,24 @@ protected ActionResult PerformPostSave(ex, contentTypeSave, ct, ctId); + TContentTypeDisplay responseEx = + CreateInvalidCompositionResponseException( + ex, contentTypeSave, ct, ctId); if (responseEx is null) + { throw ex; + } return ValidationProblem(responseEx); } - var exResult = CreateCompositionValidationExceptionIfInvalid(contentTypeSave, newCt); - if (exResult != null) return ValidationProblem(exResult); + TContentTypeDisplay exResult = + CreateCompositionValidationExceptionIfInvalid( + contentTypeSave, newCt); + if (exResult != null) + { + return ValidationProblem(exResult); + } //set id to null to ensure its handled as a new type contentTypeSave.Id = null; @@ -364,30 +420,33 @@ protected ActionResult PerformPostSave x.ModelType == modelType) - .SelectMany(x => x.Validate(model)) - .Where(x => !string.IsNullOrWhiteSpace(x.ErrorMessage) && x.MemberNames.Any()); + IEnumerable validationResults = _editorValidatorCollection + .Where(x => x.ModelType == modelType) + .SelectMany(x => x.Validate(model)) + .Where(x => !string.IsNullOrWhiteSpace(x.ErrorMessage) && x.MemberNames.Any()); - foreach (var r in validationResults) - foreach (var m in r.MemberNames) - modelState.AddModelError(m, r.ErrorMessage); + foreach (ValidationResult r in validationResults) + foreach (var m in r.MemberNames) + { + modelState.AddModelError(m, r.ErrorMessage); + } } /// - /// Move + /// Move /// /// /// @@ -398,13 +457,13 @@ protected IActionResult PerformMove( Func getContentType, Func>> doMove) { - var toMove = getContentType(move.Id); + TContentType toMove = getContentType(move.Id); if (toMove == null) { return NotFound(); } - var result = doMove(toMove, move.ParentId); + Attempt> result = doMove(toMove, move.ParentId); if (result.Success) { return Content(toMove.Path, MediaTypeNames.Text.Plain, Encoding.UTF8); @@ -424,7 +483,7 @@ protected IActionResult PerformMove( } /// - /// Move + /// Move /// /// /// @@ -435,13 +494,13 @@ protected IActionResult PerformCopy( Func getContentType, Func>> doCopy) { - var toMove = getContentType(move.Id); + TContentType toMove = getContentType(move.Id); if (toMove == null) { return NotFound(); } - var result = doCopy(toMove, move.ParentId); + Attempt> result = doCopy(toMove, move.ParentId); if (result.Success) { return Content(toMove.Path, MediaTypeNames.Text.Plain, Encoding.UTF8); @@ -461,31 +520,39 @@ protected IActionResult PerformCopy( } /// - /// Validates the composition and adds errors to the model state if any are found then throws an error response if there are errors + /// Validates the composition and adds errors to the model state if any are found then throws an error response if + /// there are errors /// /// /// /// - private TContentTypeDisplay CreateCompositionValidationExceptionIfInvalid(TContentTypeSave contentTypeSave, TContentType composition) + private TContentTypeDisplay CreateCompositionValidationExceptionIfInvalid(TContentTypeSave contentTypeSave, TContentType composition) where TContentTypeSave : ContentTypeSave where TPropertyType : PropertyTypeBasic where TContentTypeDisplay : ContentTypeCompositionDisplay { - var service = GetContentTypeService(); - var validateAttempt = service.ValidateComposition(composition); + IContentTypeBaseService service = GetContentTypeService(); + Attempt validateAttempt = service.ValidateComposition(composition); if (validateAttempt == false) { - //if it's not successful then we need to return some model state for the property aliases that - // are duplicated - var invalidPropertyAliases = validateAttempt.Result.Distinct(); - AddCompositionValidationErrors(contentTypeSave, invalidPropertyAliases); + // if it's not successful then we need to return some model state for the property type and property group + // aliases that are duplicated + IEnumerable duplicatePropertyTypeAliases = validateAttempt.Result.Distinct(); + var invalidPropertyGroupAliases = + (validateAttempt.Exception as InvalidCompositionException)?.PropertyGroupAliases ?? + Array.Empty(); + + AddCompositionValidationErrors(contentTypeSave, + duplicatePropertyTypeAliases, invalidPropertyGroupAliases); - var display = UmbracoMapper.Map(composition); + TContentTypeDisplay display = UmbracoMapper.Map(composition); //map the 'save' data on top display = UmbracoMapper.Map(contentTypeSave, display); display.Errors = ModelState.ToErrorDictionary(); return display; } + return null; } @@ -493,39 +560,62 @@ public IContentTypeBaseService GetContentTypeService() where T : IContentTypeComposition { if (typeof(T).Implements()) + { return ContentTypeService as IContentTypeBaseService; + } + if (typeof(T).Implements()) + { return MediaTypeService as IContentTypeBaseService; + } + if (typeof(T).Implements()) + { return MemberTypeService as IContentTypeBaseService; + } + throw new ArgumentException("Type " + typeof(T).FullName + " does not have a service."); } /// - /// Adds errors to the model state if any invalid aliases are found then throws an error response if there are errors + /// Adds errors to the model state if any invalid aliases are found then throws an error response if there are errors /// /// - /// + /// + /// /// - private void AddCompositionValidationErrors(TContentTypeSave contentTypeSave, IEnumerable invalidPropertyAliases) + private void AddCompositionValidationErrors(TContentTypeSave contentTypeSave, + IEnumerable duplicatePropertyTypeAliases, IEnumerable invalidPropertyGroupAliases) where TContentTypeSave : ContentTypeSave where TPropertyType : PropertyTypeBasic { - foreach (var propertyAlias in invalidPropertyAliases) + foreach (var propertyTypeAlias in duplicatePropertyTypeAliases) { - // Find the property relating to these - var property = contentTypeSave.Groups.SelectMany(x => x.Properties).Single(x => x.Alias == propertyAlias); - var group = contentTypeSave.Groups.Single(x => x.Properties.Contains(property)); + // Find the property type relating to these + TPropertyType property = contentTypeSave.Groups.SelectMany(x => x.Properties) + .Single(x => x.Alias == propertyTypeAlias); + PropertyGroupBasic group = + contentTypeSave.Groups.Single(x => x.Properties.Contains(property)); var propertyIndex = group.Properties.IndexOf(property); var groupIndex = contentTypeSave.Groups.IndexOf(group); var key = $"Groups[{groupIndex}].Properties[{propertyIndex}].Alias"; - ModelState.AddModelError(key, "Duplicate property aliases not allowed between compositions"); + ModelState.AddModelError(key, "Duplicate property aliases aren't allowed between compositions"); + } + + foreach (var propertyGroupAlias in invalidPropertyGroupAliases) + { + // Find the property group relating to these + PropertyGroupBasic group = + contentTypeSave.Groups.Single(x => x.Alias == propertyGroupAlias); + var groupIndex = contentTypeSave.Groups.IndexOf(group); + var key = $"Groups[{groupIndex}].Name"; + ModelState.AddModelError(key, "Different group types aren't allowed between compositions"); } } /// - /// If the exception is an InvalidCompositionException create a response exception to be thrown for validation errors + /// If the exception is an InvalidCompositionException create a response exception to be thrown for validation errors /// /// /// @@ -535,7 +625,8 @@ private void AddCompositionValidationErrors(TCo /// /// /// - private TContentTypeDisplay CreateInvalidCompositionResponseException( + private TContentTypeDisplay CreateInvalidCompositionResponseException( Exception ex, TContentTypeSave contentTypeSave, TContentType ct, int ctId) where TContentTypeDisplay : ContentTypeCompositionDisplay where TContentTypeSave : ContentTypeSave @@ -550,23 +641,27 @@ private TContentTypeDisplay CreateInvalidCompositionResponseException(contentTypeSave, invalidCompositionException.PropertyTypeAliases); + AddCompositionValidationErrors(contentTypeSave, + invalidCompositionException.PropertyTypeAliases, invalidCompositionException.PropertyGroupAliases); return CreateModelStateValidationEror(ctId, contentTypeSave, ct); } + return null; } /// - /// Used to throw the ModelState validation results when the ModelState is invalid + /// Used to throw the ModelState validation results when the ModelState is invalid /// /// /// /// /// /// - private TContentTypeDisplay CreateModelStateValidationEror(int ctId, TContentTypeSave contentTypeSave, TContentType ct) + private TContentTypeDisplay CreateModelStateValidationEror(int ctId, + TContentTypeSave contentTypeSave, TContentType ct) where TContentTypeDisplay : ContentTypeCompositionDisplay where TContentTypeSave : ContentTypeSave { diff --git a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs index 2eaeee3d12ec..91af3724343f 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Dynamic; using System.Globalization; using System.Linq; +using System.Linq.Expressions; using System.Reflection; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -13,6 +15,7 @@ using Umbraco.Cms.Core.Models.ContentEditing; using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Models.Membership; +using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Models.TemplateQuery; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Security; @@ -26,20 +29,22 @@ using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Cms.Web.Common.ModelBinders; using Umbraco.Extensions; -using Constants = Umbraco.Cms.Core.Constants; namespace Umbraco.Cms.Web.BackOffice.Controllers { /// - /// The API controller used for getting entity objects, basic name, icon, id representation of umbraco objects that are based on CMSNode + /// The API controller used for getting entity objects, basic name, icon, id representation of umbraco objects that are + /// based on CMSNode /// /// - /// - /// This controller allows resolving basic entity data for various entities without placing the hard restrictions on users that may not have access - /// to the sections these entities entities exist in. This is to allow pickers, etc... of data to work for all users. In some cases such as accessing - /// Members, more explicit security checks are done. - /// - /// Some objects such as macros are not based on CMSNode + /// + /// This controller allows resolving basic entity data for various entities without placing the hard restrictions + /// on users that may not have access + /// to the sections these entities entities exist in. This is to allow pickers, etc... of data to work for all + /// users. In some cases such as accessing + /// Members, more explicit security checks are done. + /// + /// Some objects such as macros are not based on CMSNode /// [PluginController(Constants.Web.Mvc.BackOfficeApiArea)] [ParameterSwapControllerActionSelector(nameof(GetAncestors), "id", typeof(int), typeof(Guid))] @@ -51,26 +56,28 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers [ParameterSwapControllerActionSelector(nameof(GetUrl), "id", typeof(int), typeof(Udi))] public class EntityController : UmbracoAuthorizedJsonController { - private readonly ITreeService _treeService; - private readonly UmbracoTreeSearcher _treeSearcher; - private readonly SearchableTreeCollection _searchableTreeCollection; - private readonly IPublishedContentQuery _publishedContentQuery; - private readonly IShortStringHelper _shortStringHelper; - private readonly IEntityService _entityService; + private static readonly string[] _postFilterSplitStrings = { "=", "==", "!=", "<>", ">", "<", ">=", "<=" }; + + private readonly AppCaches _appCaches; private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor; - private readonly IPublishedUrlProvider _publishedUrlProvider; private readonly IContentService _contentService; - private readonly IUmbracoMapper _umbracoMapper; + private readonly IContentTypeService _contentTypeService; private readonly IDataTypeService _dataTypeService; - private readonly ISqlContext _sqlContext; - private readonly ILocalizedTextService _localizedTextService; + private readonly IEntityService _entityService; private readonly IFileService _fileService; - private readonly IContentTypeService _contentTypeService; - private readonly IMediaTypeService _mediaTypeService; + private readonly ILocalizationService _localizationService; + private readonly ILocalizedTextService _localizedTextService; private readonly IMacroService _macroService; + private readonly IMediaTypeService _mediaTypeService; + private readonly IPublishedContentQuery _publishedContentQuery; + private readonly IPublishedUrlProvider _publishedUrlProvider; + private readonly SearchableTreeCollection _searchableTreeCollection; + private readonly IShortStringHelper _shortStringHelper; + private readonly ISqlContext _sqlContext; + private readonly UmbracoTreeSearcher _treeSearcher; + private readonly ITreeService _treeService; + private readonly IUmbracoMapper _umbracoMapper; private readonly IUserService _userService; - private readonly ILocalizationService _localizationService; - private readonly AppCaches _appCaches; public EntityController( ITreeService treeService, @@ -102,7 +109,8 @@ public EntityController( publishedContentQuery ?? throw new ArgumentNullException(nameof(publishedContentQuery)); _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); - _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? + throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _publishedUrlProvider = publishedUrlProvider ?? throw new ArgumentNullException(nameof(publishedUrlProvider)); _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); @@ -120,16 +128,19 @@ public EntityController( _appCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches)); } + /// - /// Returns an Umbraco alias given a string + /// Returns an Umbraco alias given a string /// /// /// /// public dynamic GetSafeAlias(string value, bool camelCase = true) { - var returnValue = string.IsNullOrWhiteSpace(value) ? string.Empty : value.ToSafeAlias(_shortStringHelper, camelCase); - dynamic returnObj = new System.Dynamic.ExpandoObject(); + var returnValue = string.IsNullOrWhiteSpace(value) + ? string.Empty + : value.ToSafeAlias(_shortStringHelper, camelCase); + dynamic returnObj = new ExpandoObject(); returnObj.alias = returnValue; returnObj.original = value; returnObj.camelCase = camelCase; @@ -138,41 +149,47 @@ public dynamic GetSafeAlias(string value, bool camelCase = true) } /// - /// Searches for results based on the entity type + /// Searches for results based on the entity type /// /// /// /// - /// A starting point for the search, generally a node id, but for members this is a member type alias + /// A starting point for the search, generally a node id, but for members this is a member type alias /// /// If set used to look up whether user and group start node permissions will be ignored. /// [HttpGet] - public IEnumerable Search(string query, UmbracoEntityTypes type, string searchFrom = null, Guid? dataTypeKey = null) + public IEnumerable Search(string query, UmbracoEntityTypes type, string searchFrom = null, + Guid? dataTypeKey = null) { // NOTE: Theoretically you shouldn't be able to see member data if you don't have access to members right? ... but there is a member picker, so can't really do that if (string.IsNullOrEmpty(query)) + { return Enumerable.Empty(); + } //TODO: This uses the internal UmbracoTreeSearcher, this instead should delgate to the ISearchableTree implementation for the type - var ignoreUserStartNodes = dataTypeKey.HasValue && _dataTypeService.IsDataTypeIgnoringUserStartNodes(dataTypeKey.Value); + var ignoreUserStartNodes = dataTypeKey.HasValue && + _dataTypeService.IsDataTypeIgnoringUserStartNodes(dataTypeKey.Value); return ExamineSearch(query, type, searchFrom, ignoreUserStartNodes); } /// - /// Searches for all content that the user is allowed to see (based on their allowed sections) + /// Searches for all content that the user is allowed to see (based on their allowed sections) /// /// /// /// - /// Even though a normal entity search will allow any user to search on a entity type that they may not have access to edit, we need - /// to filter these results to the sections they are allowed to edit since this search function is explicitly for the global search - /// so if we showed entities that they weren't allowed to edit they would get errors when clicking on the result. - /// - /// The reason a user is allowed to search individual entity types that they are not allowed to edit is because those search - /// methods might be used in things like pickers in the content editor. + /// Even though a normal entity search will allow any user to search on a entity type that they may not have access to + /// edit, we need + /// to filter these results to the sections they are allowed to edit since this search function is explicitly for the + /// global search + /// so if we showed entities that they weren't allowed to edit they would get errors when clicking on the result. + /// The reason a user is allowed to search individual entity types that they are not allowed to edit is because those + /// search + /// methods might be used in things like pickers in the content editor. /// [HttpGet] public IDictionary SearchAll(string query) @@ -180,16 +197,22 @@ public IDictionary SearchAll(string query) var result = new Dictionary(); if (string.IsNullOrEmpty(query)) + { return result; + } var allowedSections = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.AllowedSections.ToArray(); - foreach (var searchableTree in _searchableTreeCollection.SearchableApplicationTrees.OrderBy(t => t.Value.SortOrder)) + foreach (KeyValuePair searchableTree in _searchableTreeCollection + .SearchableApplicationTrees.OrderBy(t => t.Value.SortOrder)) { if (allowedSections.Contains(searchableTree.Value.AppAlias)) { - var tree = _treeService.GetByAlias(searchableTree.Key); - if (tree == null) continue; //shouldn't occur + Tree tree = _treeService.GetByAlias(searchableTree.Key); + if (tree == null) + { + continue; //shouldn't occur + } result[Tree.GetRootNodeDisplayName(tree, _localizedTextService)] = new TreeSearchResult { @@ -201,49 +224,52 @@ public IDictionary SearchAll(string query) }; } } + return result; } /// - /// Gets the path for a given node ID + /// Gets the path for a given node ID /// /// /// /// public IConvertToActionResult GetPath(int id, UmbracoEntityTypes type) { - var foundContentResult = GetResultForId(id, type); - var foundContent = foundContentResult.Value; + ActionResult foundContentResult = GetResultForId(id, type); + EntityBasic foundContent = foundContentResult.Value; if (foundContent is null) { return foundContentResult; } - return new ActionResult>(foundContent.Path.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries).Select( - s => int.Parse(s, CultureInfo.InvariantCulture))); + return new ActionResult>(foundContent.Path + .Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries).Select( + s => int.Parse(s, CultureInfo.InvariantCulture))); } /// - /// Gets the path for a given node ID + /// Gets the path for a given node ID /// /// /// /// public IConvertToActionResult GetPath(Guid id, UmbracoEntityTypes type) { - var foundContentResult = GetResultForKey(id, type); - var foundContent = foundContentResult.Value; + ActionResult foundContentResult = GetResultForKey(id, type); + EntityBasic foundContent = foundContentResult.Value; if (foundContent is null) { return foundContentResult; } - return new ActionResult>(foundContent.Path.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries).Select( - s => int.Parse(s, CultureInfo.InvariantCulture))); + return new ActionResult>(foundContent.Path + .Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries).Select( + s => int.Parse(s, CultureInfo.InvariantCulture))); } /// - /// Gets the path for a given node ID + /// Gets the path for a given node ID /// /// /// @@ -260,16 +286,19 @@ public IActionResult GetPath(Udi id, UmbracoEntityTypes type) } /// - /// Gets the URL of an entity + /// Gets the URL of an entity /// /// UDI of the entity to fetch URL for /// The culture to fetch the URL for /// The URL or path to the item public IActionResult GetUrl(Udi id, string culture = "*") { - var intId = _entityService.GetId(id); + Attempt intId = _entityService.GetId(id); if (!intId.Success) + { return NotFound(); + } + UmbracoEntityTypes entityType; switch (id.EntityType) { @@ -285,18 +314,61 @@ public IActionResult GetUrl(Udi id, string culture = "*") default: return NotFound(); } + return GetUrl(intId.Result, entityType, culture); } /// - /// Gets the URL of an entity + /// Get entity URLs by UDIs + /// + /// + /// A list of UDIs to lookup items by + /// + /// The culture to fetch the URL for + /// Dictionary mapping Udi -> Url + /// + /// We allow for POST because there could be quite a lot of Ids. + /// + [HttpGet] + [HttpPost] + public IDictionary GetUrlsByUdis([FromJsonPath] Udi[] udis, string culture = null) + { + if (udis == null || udis.Length == 0) + { + return new Dictionary(); + } + + // TODO: PMJ 2021-09-27 - Should GetUrl(Udi) exist as an extension method on UrlProvider/IUrlProvider (in v9) + string MediaOrDocumentUrl(Udi udi) + { + if (udi is not GuidUdi guidUdi) + { + return null; + } + + return guidUdi.EntityType switch + { + Constants.UdiEntityType.Document => _publishedUrlProvider.GetUrl(guidUdi.Guid, + culture: culture ?? ClientCulture()), + // NOTE: If culture is passed here we get an empty string rather than a media item URL WAT + Constants.UdiEntityType.Media => _publishedUrlProvider.GetMediaUrl(guidUdi.Guid, culture: null), + _ => null + }; + } + + return udis + .Select(udi => new { Udi = udi, Url = MediaOrDocumentUrl(udi) }).ToDictionary(x => x.Udi, x => x.Url); + } + + /// + /// Gets the URL of an entity /// /// Int id of the entity to fetch URL for /// The type of entity such as Document, Media, Member /// The culture to fetch the URL for /// The URL or path to the item /// - /// We are not restricting this with security because there is no sensitive data + /// We are not restricting this with security because there is no sensitive data /// public IActionResult GetUrl(int id, UmbracoEntityTypes type, string culture = null) { @@ -315,7 +387,7 @@ public IActionResult GetUrl(int id, UmbracoEntityTypes type, string culture = nu } } - var ancestors = GetResultForAncestors(id, type); + IEnumerable ancestors = GetResultForAncestors(id, type); //if content, skip the first node for replicating NiceUrl defaults if (type == UmbracoEntityTypes.Document) @@ -330,7 +402,7 @@ public IActionResult GetUrl(int id, UmbracoEntityTypes type, string culture = nu /// - /// Gets an entity by a xpath query + /// Gets an entity by a xpath query /// /// /// @@ -342,48 +414,53 @@ public ActionResult GetByQuery(string query, int nodeContextId, Umb if (type != UmbracoEntityTypes.Document) + { throw new ArgumentException("Get by query is only compatible with entities of type Document"); + } var q = ParseXPathQuery(query, nodeContextId); - var node = _publishedContentQuery.ContentSingleAtXPath(q); + IPublishedContent node = _publishedContentQuery.ContentSingleAtXPath(q); if (node == null) + { return null; + } return GetById(node.Id, type); } // PP: Work in progress on the query parser - private string ParseXPathQuery(string query, int id) - { - return UmbracoXPathPathSyntaxParser.ParseXPathQuery( - xpathExpression: query, - nodeContextId: id, - getPath: nodeid => + private string ParseXPathQuery(string query, int id) => + UmbracoXPathPathSyntaxParser.ParseXPathQuery( + query, + id, + nodeid => { - var ent = _entityService.Get(nodeid); + IEntitySlim ent = _entityService.Get(nodeid); return ent.Path.Split(Constants.CharArrays.Comma).Reverse(); }, - publishedContentExists: i => _publishedContentQuery.Content(i) != null); - } + i => _publishedContentQuery.Content(i) != null); [HttpGet] public ActionResult GetUrlAndAnchors(Udi id, string culture = "*") { - var intId = _entityService.GetId(id); + Attempt intId = _entityService.GetId(id); if (!intId.Success) + { return NotFound(); + } return GetUrlAndAnchors(intId.Result, culture); } + [HttpGet] public UrlAndAnchors GetUrlAndAnchors(int id, string culture = "*") { culture = culture ?? ClientCulture(); var url = _publishedUrlProvider.GetUrl(id, culture: culture); - var anchorValues = _contentService.GetAnchorValuesFromRTEs(id, culture); + IEnumerable anchorValues = _contentService.GetAnchorValuesFromRTEs(id, culture); return new UrlAndAnchors(url, anchorValues); } @@ -391,137 +468,13 @@ public UrlAndAnchors GetUrlAndAnchors(int id, string culture = "*") [HttpPost] public IEnumerable GetAnchors(AnchorsModel model) { - var anchorValues = _contentService.GetAnchorValuesFromRTEContent(model.RteContent); + IEnumerable anchorValues = _contentService.GetAnchorValuesFromRTEContent(model.RteContent); return anchorValues; } - - #region GetById - - /// - /// Gets an entity by it's id - /// - /// - /// - /// - public ActionResult GetById(int id, UmbracoEntityTypes type) - { - return GetResultForId(id, type); - } - - /// - /// Gets an entity by it's key - /// - /// - /// - /// - public ActionResult GetById(Guid id, UmbracoEntityTypes type) - { - return GetResultForKey(id, type); - } - - /// - /// Gets an entity by it's UDI - /// - /// - /// - /// - public ActionResult GetById(Udi id, UmbracoEntityTypes type) - { - var guidUdi = id as GuidUdi; - if (guidUdi != null) - { - return GetResultForKey(guidUdi.Guid, type); - } - - return NotFound(); - } - #endregion - - #region GetByIds - /// - /// Get entities by integer ids - /// - /// - /// - /// - /// - /// We allow for POST because there could be quite a lot of Ids - /// - [HttpGet] - [HttpPost] - public ActionResult> GetByIds([FromJsonPath]int[] ids, [FromQuery]UmbracoEntityTypes type) - { - if (ids == null) - { - return NotFound(); - } - - return new ActionResult>(GetResultForIds(ids, type)); - } - - /// - /// Get entities by GUID ids - /// - /// - /// - /// - /// - /// We allow for POST because there could be quite a lot of Ids - /// - [HttpGet] - [HttpPost] - public ActionResult> GetByIds([FromJsonPath]Guid[] ids, [FromQuery]UmbracoEntityTypes type) - { - if (ids == null) - { - return NotFound(); - } - - return new ActionResult>(GetResultForKeys(ids, type)); - } - - /// - /// Get entities by UDIs - /// - /// - /// A list of UDIs to lookup items by, all UDIs must be of the same UDI type! - /// - /// - /// - /// - /// We allow for POST because there could be quite a lot of Ids. - /// - [HttpGet] - [HttpPost] - public ActionResult> GetByIds([FromJsonPath]Udi[] ids, [FromQuery]UmbracoEntityTypes type) - { - if (ids == null) - { - return NotFound(); - } - - if (ids.Length == 0) - { - return Enumerable.Empty().ToList(); - } - - //all udi types will need to be the same in this list so we'll determine by the first - //currently we only support GuidUdi for this method - - var guidUdi = ids[0] as GuidUdi; - if (guidUdi != null) - { - return new ActionResult>(GetResultForKeys(ids.Select(x => ((GuidUdi)x).Guid).ToArray(), type)); - } - - return NotFound(); - } - #endregion - public IEnumerable GetChildren(int id, UmbracoEntityTypes type, Guid? dataTypeKey = null) { - var objectType = ConvertToObjectType(type); + UmbracoObjectTypes? objectType = ConvertToObjectType(type); if (objectType.HasValue) { //TODO: Need to check for Object types that support hierarchy here, some might not. @@ -531,11 +484,15 @@ public IEnumerable GetChildren(int id, UmbracoEntityTypes type, Gui var ignoreUserStartNodes = IsDataTypeIgnoringUserStartNodes(dataTypeKey); // root is special: we reduce it to start nodes if the user's start node is not the default, then we need to return their start nodes - if (id == Constants.System.Root && startNodes.Length > 0 && startNodes.Contains(Constants.System.Root) == false && !ignoreUserStartNodes) + if (id == Constants.System.Root && startNodes.Length > 0 && + startNodes.Contains(Constants.System.Root) == false && !ignoreUserStartNodes) { - var nodes = _entityService.GetAll(objectType.Value, startNodes).ToArray(); + IEntitySlim[] nodes = _entityService.GetAll(objectType.Value, startNodes).ToArray(); if (nodes.Length == 0) + { return Enumerable.Empty(); + } + var pr = new List(nodes.Select(_umbracoMapper.Map)); return pr; } @@ -546,6 +503,7 @@ public IEnumerable GetChildren(int id, UmbracoEntityTypes type, Gui .WhereNotNull() .Select(_umbracoMapper.Map); } + //now we need to convert the unknown ones switch (type) { @@ -553,12 +511,13 @@ public IEnumerable GetChildren(int id, UmbracoEntityTypes type, Gui case UmbracoEntityTypes.User: case UmbracoEntityTypes.Macro: default: - throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + type); + throw new NotSupportedException("The " + typeof(EntityController) + + " does not currently support data for the type " + type); } } /// - /// Get paged child entities by id + /// Get paged child entities by id /// /// /// @@ -602,7 +561,8 @@ public ActionResult> GetPagedChildren( //the EntityService can search paged members from the root intId = -1; - return GetPagedChildren(intId, type, pageNumber, pageSize, orderBy, orderDirection, filter, dataTypeKey); + return GetPagedChildren(intId, type, pageNumber, pageSize, orderBy, orderDirection, filter, + dataTypeKey); } //the EntityService cannot search members of a certain type, this is currently not supported and would require @@ -611,16 +571,14 @@ public ActionResult> GetPagedChildren( //TODO: We should really fix this in the EntityService but if we don't we should allow the ISearchableTree for the members controller // to be used for this search instead of the built in/internal searcher - var searchResult = _treeSearcher.ExamineSearch(filter ?? "", type, pageSize, pageNumber - 1, out long total, null, id); + IEnumerable searchResult = _treeSearcher.ExamineSearch(filter ?? "", type, pageSize, + pageNumber - 1, out var total, null, id); - return new PagedResult(total, pageNumber, pageSize) - { - Items = searchResult - }; + return new PagedResult(total, pageNumber, pageSize) { Items = searchResult }; } /// - /// Get paged child entities by id + /// Get paged child entities by id /// /// /// @@ -641,11 +599,16 @@ public ActionResult> GetPagedChildren( Guid? dataTypeKey = null) { if (pageNumber <= 0) + { return NotFound(); + } + if (pageSize <= 0) + { return NotFound(); + } - var objectType = ConvertToObjectType(type); + UmbracoObjectTypes? objectType = ConvertToObjectType(type); if (objectType.HasValue) { IEnumerable entities; @@ -656,14 +619,25 @@ public ActionResult> GetPagedChildren( var ignoreUserStartNodes = IsDataTypeIgnoringUserStartNodes(dataTypeKey); // root is special: we reduce it to start nodes if the user's start node is not the default, then we need to return their start nodes - if (id == Constants.System.Root && startNodes.Length > 0 && startNodes.Contains(Constants.System.Root) == false && !ignoreUserStartNodes) + if (id == Constants.System.Root && startNodes.Length > 0 && + startNodes.Contains(Constants.System.Root) == false && !ignoreUserStartNodes) { if (pageNumber > 0) + { return new PagedResult(0, 0, 0); - var nodes = _entityService.GetAll(objectType.Value, startNodes).ToArray(); + } + + IEntitySlim[] nodes = _entityService.GetAll(objectType.Value, startNodes).ToArray(); if (nodes.Length == 0) + { return new PagedResult(0, 0, 0); - if (pageSize < nodes.Length) pageSize = nodes.Length; // bah + } + + if (pageSize < nodes.Length) + { + pageSize = nodes.Length; // bah + } + var pr = new PagedResult(nodes.Length, pageNumber, pageSize) { Items = nodes.Select(_umbracoMapper.Map) @@ -672,7 +646,8 @@ public ActionResult> GetPagedChildren( } // else proceed as usual - entities = _entityService.GetPagedChildren(id, objectType.Value, pageNumber - 1, pageSize, out totalRecords, + entities = _entityService.GetPagedChildren(id, objectType.Value, pageNumber - 1, pageSize, + out totalRecords, filter.IsNullOrWhiteSpace() ? null : _sqlContext.Query().Where(x => x.Name.Contains(filter)), @@ -689,7 +664,7 @@ public ActionResult> GetPagedChildren( { Items = entities.Select(source => { - var target = _umbracoMapper.Map(source, context => + EntityBasic target = _umbracoMapper.Map(source, context => { context.SetCulture(culture); context.SetCulture(culture); @@ -712,7 +687,8 @@ public ActionResult> GetPagedChildren( case UmbracoEntityTypes.User: case UmbracoEntityTypes.Macro: default: - throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + type); + throw new NotSupportedException("The " + typeof(EntityController) + + " does not currently support data for the type " + type); } } @@ -721,9 +697,11 @@ private int[] GetStartNodes(UmbracoEntityTypes type) switch (type) { case UmbracoEntityTypes.Document: - return _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService, _appCaches); + return _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.CalculateContentStartNodeIds( + _entityService, _appCaches); case UmbracoEntityTypes.Media: - return _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService, _appCaches); + return _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.CalculateMediaStartNodeIds( + _entityService, _appCaches); default: return Array.Empty(); } @@ -740,14 +718,19 @@ public ActionResult> GetPagedDescendants( Guid? dataTypeKey = null) { if (pageNumber <= 0) + { return NotFound(); + } + if (pageSize <= 0) + { return NotFound(); + } // re-normalize since NULL can be passed in filter = filter ?? string.Empty; - var objectType = ConvertToObjectType(type); + UmbracoObjectTypes? objectType = ConvertToObjectType(type); if (objectType.HasValue) { IEnumerable entities; @@ -757,20 +740,23 @@ public ActionResult> GetPagedDescendants( { // root is special: we reduce it to start nodes - int[] aids = GetStartNodes(type); + var aids = GetStartNodes(type); var ignoreUserStartNodes = IsDataTypeIgnoringUserStartNodes(dataTypeKey); entities = aids == null || aids.Contains(Constants.System.Root) || ignoreUserStartNodes - ? _entityService.GetPagedDescendants(objectType.Value, pageNumber - 1, pageSize, out totalRecords, + ? _entityService.GetPagedDescendants(objectType.Value, pageNumber - 1, pageSize, + out totalRecords, _sqlContext.Query().Where(x => x.Name.Contains(filter)), - Ordering.By(orderBy, orderDirection), includeTrashed: false) - : _entityService.GetPagedDescendants(aids, objectType.Value, pageNumber - 1, pageSize, out totalRecords, + Ordering.By(orderBy, orderDirection), false) + : _entityService.GetPagedDescendants(aids, objectType.Value, pageNumber - 1, pageSize, + out totalRecords, _sqlContext.Query().Where(x => x.Name.Contains(filter)), Ordering.By(orderBy, orderDirection)); } else { - entities = _entityService.GetPagedDescendants(id, objectType.Value, pageNumber - 1, pageSize, out totalRecords, + entities = _entityService.GetPagedDescendants(id, objectType.Value, pageNumber - 1, pageSize, + out totalRecords, _sqlContext.Query().Where(x => x.Name.Contains(filter)), Ordering.By(orderBy, orderDirection)); } @@ -797,20 +783,26 @@ public ActionResult> GetPagedDescendants( case UmbracoEntityTypes.User: case UmbracoEntityTypes.Macro: default: - throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + type); + throw new NotSupportedException("The " + typeof(EntityController) + + " does not currently support data for the type " + type); } } - private bool IsDataTypeIgnoringUserStartNodes(Guid? dataTypeKey) => dataTypeKey.HasValue && _dataTypeService.IsDataTypeIgnoringUserStartNodes(dataTypeKey.Value); + private bool IsDataTypeIgnoringUserStartNodes(Guid? dataTypeKey) => dataTypeKey.HasValue && + _dataTypeService + .IsDataTypeIgnoringUserStartNodes( + dataTypeKey.Value); - public IEnumerable GetAncestors(int id, UmbracoEntityTypes type, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormCollection queryStrings) - { - return GetResultForAncestors(id, type, queryStrings); - } + public IEnumerable GetAncestors(int id, UmbracoEntityTypes type, + [ModelBinder(typeof(HttpQueryStringModelBinder))] + FormCollection queryStrings) => + GetResultForAncestors(id, type, queryStrings); - public ActionResult> GetAncestors(Guid id, UmbracoEntityTypes type, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormCollection queryStrings) + public ActionResult> GetAncestors(Guid id, UmbracoEntityTypes type, + [ModelBinder(typeof(HttpQueryStringModelBinder))] + FormCollection queryStrings) { - var entity = _entityService.Get(id); + IEntitySlim entity = _entityService.Get(id); if (entity is null) { return NotFound(); @@ -820,22 +812,24 @@ public ActionResult> GetAncestors(Guid id, UmbracoEntit } /// - /// Searches for results based on the entity type + /// Searches for results based on the entity type /// /// /// /// /// If set to true, user and group start node permissions will be ignored. /// - private IEnumerable ExamineSearch(string query, UmbracoEntityTypes entityType, string searchFrom = null, bool ignoreUserStartNodes = false) + private IEnumerable ExamineSearch(string query, UmbracoEntityTypes entityType, + string searchFrom = null, bool ignoreUserStartNodes = false) { var culture = ClientCulture(); - return _treeSearcher.ExamineSearch(query, entityType, 200, 0, out _, culture, searchFrom, ignoreUserStartNodes); + return _treeSearcher.ExamineSearch(query, entityType, 200, 0, out _, culture, searchFrom, + ignoreUserStartNodes); } private IEnumerable GetResultForChildren(int id, UmbracoEntityTypes entityType) { - var objectType = ConvertToObjectType(entityType); + UmbracoObjectTypes? objectType = ConvertToObjectType(entityType); if (objectType.HasValue) { // TODO: Need to check for Object types that support hierarchic here, some might not. @@ -844,6 +838,7 @@ private IEnumerable GetResultForChildren(int id, UmbracoEntityTypes .WhereNotNull() .Select(MapEntities()); } + //now we need to convert the unknown ones switch (entityType) { @@ -851,30 +846,37 @@ private IEnumerable GetResultForChildren(int id, UmbracoEntityTypes case UmbracoEntityTypes.User: case UmbracoEntityTypes.Macro: default: - throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + entityType); + throw new NotSupportedException("The " + typeof(EntityController) + + " does not currently support data for the type " + entityType); } } - private IEnumerable GetResultForAncestors(int id, UmbracoEntityTypes entityType, FormCollection queryStrings = null) + private IEnumerable GetResultForAncestors(int id, UmbracoEntityTypes entityType, + FormCollection queryStrings = null) { - var objectType = ConvertToObjectType(entityType); + UmbracoObjectTypes? objectType = ConvertToObjectType(entityType); if (objectType.HasValue) { // TODO: Need to check for Object types that support hierarchic here, some might not. - var ids = _entityService.Get(id).Path.Split(Constants.CharArrays.Comma).Select(s => int.Parse(s, CultureInfo.InvariantCulture)).Distinct().ToArray(); + var ids = _entityService.Get(id).Path.Split(Constants.CharArrays.Comma) + .Select(s => int.Parse(s, CultureInfo.InvariantCulture)).Distinct().ToArray(); - var ignoreUserStartNodes = IsDataTypeIgnoringUserStartNodes(queryStrings?.GetValue("dataTypeId")); + var ignoreUserStartNodes = + IsDataTypeIgnoringUserStartNodes(queryStrings?.GetValue("dataTypeId")); if (ignoreUserStartNodes == false) { int[] aids = null; switch (entityType) { case UmbracoEntityTypes.Document: - aids = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService, _appCaches); + aids = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser + .CalculateContentStartNodeIds(_entityService, _appCaches); break; case UmbracoEntityTypes.Media: - aids = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService, _appCaches); + aids = + _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.CalculateMediaStartNodeIds( + _entityService, _appCaches); break; } @@ -889,12 +891,14 @@ private IEnumerable GetResultForAncestors(int id, UmbracoEntityType lids.Add(i); continue; } + if (aids.Contains(i)) { lids.Add(i); ok = true; } } + ids = lids.ToArray(); } } @@ -908,6 +912,7 @@ private IEnumerable GetResultForAncestors(int id, UmbracoEntityType .OrderBy(x => x.Level) .Select(MapEntities(culture)); } + //now we need to convert the unknown ones switch (entityType) { @@ -917,28 +922,33 @@ private IEnumerable GetResultForAncestors(int id, UmbracoEntityType case UmbracoEntityTypes.User: case UmbracoEntityTypes.Macro: default: - throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + entityType); + throw new NotSupportedException("The " + typeof(EntityController) + + " does not currently support data for the type " + entityType); } } private IEnumerable GetResultForKeys(Guid[] keys, UmbracoEntityTypes entityType) { if (keys.Length == 0) + { return Enumerable.Empty(); + } - var objectType = ConvertToObjectType(entityType); + UmbracoObjectTypes? objectType = ConvertToObjectType(entityType); if (objectType.HasValue) { - var entities = _entityService.GetAll(objectType.Value, keys) + IEnumerable entities = _entityService.GetAll(objectType.Value, keys) .WhereNotNull() .Select(MapEntities()); // entities are in "some" order, put them back in order var xref = entities.ToDictionary(x => x.Key); - var result = keys.Select(x => xref.ContainsKey(x) ? xref[x] : null).Where(x => x != null); + IEnumerable result = keys.Select(x => xref.ContainsKey(x) ? xref[x] : null) + .Where(x => x != null); return result; } + //now we need to convert the unknown ones switch (entityType) { @@ -948,28 +958,33 @@ private IEnumerable GetResultForKeys(Guid[] keys, UmbracoEntityType case UmbracoEntityTypes.User: case UmbracoEntityTypes.Macro: default: - throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + entityType); + throw new NotSupportedException("The " + typeof(EntityController) + + " does not currently support data for the type " + entityType); } } private IEnumerable GetResultForIds(int[] ids, UmbracoEntityTypes entityType) { if (ids.Length == 0) + { return Enumerable.Empty(); + } - var objectType = ConvertToObjectType(entityType); + UmbracoObjectTypes? objectType = ConvertToObjectType(entityType); if (objectType.HasValue) { - var entities = _entityService.GetAll(objectType.Value, ids) + IEnumerable entities = _entityService.GetAll(objectType.Value, ids) .WhereNotNull() .Select(MapEntities()); // entities are in "some" order, put them back in order var xref = entities.ToDictionary(x => x.Id); - var result = ids.Select(x => xref.ContainsKey(x) ? xref[x] : null).Where(x => x != null); + IEnumerable result = ids.Select(x => xref.ContainsKey(x) ? xref[x] : null) + .Where(x => x != null); return result; } + //now we need to convert the unknown ones switch (entityType) { @@ -979,22 +994,25 @@ private IEnumerable GetResultForIds(int[] ids, UmbracoEntityTypes e case UmbracoEntityTypes.User: case UmbracoEntityTypes.Macro: default: - throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + entityType); + throw new NotSupportedException("The " + typeof(EntityController) + + " does not currently support data for the type " + entityType); } } private ActionResult GetResultForKey(Guid key, UmbracoEntityTypes entityType) { - var objectType = ConvertToObjectType(entityType); + UmbracoObjectTypes? objectType = ConvertToObjectType(entityType); if (objectType.HasValue) { - var found = _entityService.Get(key, objectType.Value); + IEntitySlim found = _entityService.Get(key, objectType.Value); if (found == null) { return NotFound(); } + return _umbracoMapper.Map(found); } + //now we need to convert the unknown ones switch (entityType) { @@ -1009,22 +1027,25 @@ private ActionResult GetResultForKey(Guid key, UmbracoEntityTypes e case UmbracoEntityTypes.Macro: default: - throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + entityType); + throw new NotSupportedException("The " + typeof(EntityController) + + " does not currently support data for the type " + entityType); } } private ActionResult GetResultForId(int id, UmbracoEntityTypes entityType) { - var objectType = ConvertToObjectType(entityType); + UmbracoObjectTypes? objectType = ConvertToObjectType(entityType); if (objectType.HasValue) { - var found = _entityService.Get(id, objectType.Value); + IEntitySlim found = _entityService.Get(id, objectType.Value); if (found == null) { return NotFound(); } + return MapEntity(found); } + //now we need to convert the unknown ones switch (entityType) { @@ -1039,7 +1060,8 @@ private ActionResult GetResultForId(int id, UmbracoEntityTypes enti case UmbracoEntityTypes.Macro: default: - throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + entityType); + throw new NotSupportedException("The " + typeof(EntityController) + + " does not currently support data for the type " + entityType); } } @@ -1070,145 +1092,151 @@ private ActionResult GetResultForId(int id, UmbracoEntityTypes enti } /// - /// /// /// The type of entity. - /// Optional filter - Format like: "BoolVariable==true&IntVariable>=6". Invalid filters are ignored. + /// + /// Optional filter - Format like: "BoolVariable==true&IntVariable>=6". Invalid filters are + /// ignored. + /// /// - public IEnumerable GetAll(UmbracoEntityTypes type, string postFilter) - { - return GetResultForAll(type, postFilter); - } + public IEnumerable GetAll(UmbracoEntityTypes type, string postFilter) => + GetResultForAll(type, postFilter); /// - /// Gets the result for the entity list based on the type + /// Gets the result for the entity list based on the type /// /// /// A string where filter that will filter the results dynamically with linq - optional /// private IEnumerable GetResultForAll(UmbracoEntityTypes entityType, string postFilter = null) { - var objectType = ConvertToObjectType(entityType); + UmbracoObjectTypes? objectType = ConvertToObjectType(entityType); if (objectType.HasValue) { // TODO: Should we order this by something ? - var entities = _entityService.GetAll(objectType.Value).WhereNotNull().Select(MapEntities()); + IEnumerable entities = + _entityService.GetAll(objectType.Value).WhereNotNull().Select(MapEntities()); return ExecutePostFilter(entities, postFilter); } + //now we need to convert the unknown ones switch (entityType) { case UmbracoEntityTypes.Template: - var templates = _fileService.GetTemplates(); - var filteredTemplates = ExecutePostFilter(templates, postFilter); + IEnumerable templates = _fileService.GetTemplates(); + IEnumerable filteredTemplates = ExecutePostFilter(templates, postFilter); return filteredTemplates.Select(MapEntities()); case UmbracoEntityTypes.Macro: //Get all macros from the macro service - var macros = _macroService.GetAll().WhereNotNull().OrderBy(x => x.Name); - var filteredMacros = ExecutePostFilter(macros, postFilter); + IOrderedEnumerable macros = _macroService.GetAll().WhereNotNull().OrderBy(x => x.Name); + IEnumerable filteredMacros = ExecutePostFilter(macros, postFilter); return filteredMacros.Select(MapEntities()); case UmbracoEntityTypes.PropertyType: //get all document types, then combine all property types into one list - var propertyTypes = _contentTypeService.GetAll().Cast() - .Concat(_mediaTypeService.GetAll()) - .ToArray() - .SelectMany(x => x.PropertyTypes) - .DistinctBy(composition => composition.Alias); - var filteredPropertyTypes = ExecutePostFilter(propertyTypes, postFilter); + IEnumerable propertyTypes = _contentTypeService.GetAll() + .Cast() + .Concat(_mediaTypeService.GetAll()) + .ToArray() + .SelectMany(x => x.PropertyTypes) + .DistinctBy(composition => composition.Alias); + IEnumerable filteredPropertyTypes = ExecutePostFilter(propertyTypes, postFilter); return _umbracoMapper.MapEnumerable(filteredPropertyTypes); case UmbracoEntityTypes.PropertyGroup: //get all document types, then combine all property types into one list - var propertyGroups = _contentTypeService.GetAll().Cast() - .Concat(_mediaTypeService.GetAll()) - .ToArray() - .SelectMany(x => x.PropertyGroups) - .DistinctBy(composition => composition.Name); - var filteredpropertyGroups = ExecutePostFilter(propertyGroups, postFilter); + IEnumerable propertyGroups = _contentTypeService.GetAll() + .Cast() + .Concat(_mediaTypeService.GetAll()) + .ToArray() + .SelectMany(x => x.PropertyGroups) + .DistinctBy(composition => composition.Name); + IEnumerable filteredpropertyGroups = ExecutePostFilter(propertyGroups, postFilter); return _umbracoMapper.MapEnumerable(filteredpropertyGroups); case UmbracoEntityTypes.User: - var users = _userService.GetAll(0, int.MaxValue, out _); - var filteredUsers = ExecutePostFilter(users, postFilter); + IEnumerable users = _userService.GetAll(0, int.MaxValue, out _); + IEnumerable filteredUsers = ExecutePostFilter(users, postFilter); return _umbracoMapper.MapEnumerable(filteredUsers); case UmbracoEntityTypes.Stylesheet: if (!postFilter.IsNullOrWhiteSpace()) + { throw new NotSupportedException("Filtering on stylesheets is not currently supported"); + } return _fileService.GetStylesheets().Select(MapEntities()); case UmbracoEntityTypes.Script: if (!postFilter.IsNullOrWhiteSpace()) + { throw new NotSupportedException("Filtering on scripts is not currently supported"); + } return _fileService.GetScripts().Select(MapEntities()); case UmbracoEntityTypes.PartialView: if (!postFilter.IsNullOrWhiteSpace()) + { throw new NotSupportedException("Filtering on partial views is not currently supported"); + } return _fileService.GetPartialViews().Select(MapEntities()); case UmbracoEntityTypes.Language: if (!postFilter.IsNullOrWhiteSpace()) + { throw new NotSupportedException("Filtering on languages is not currently supported"); + } return _localizationService.GetAllLanguages().Select(MapEntities()); case UmbracoEntityTypes.DictionaryItem: if (!postFilter.IsNullOrWhiteSpace()) + { throw new NotSupportedException("Filtering on dictionary items is not currently supported"); + } return GetAllDictionaryItems(); default: - throw new NotSupportedException("The " + typeof(EntityController) + " does not currently support data for the type " + entityType); + throw new NotSupportedException("The " + typeof(EntityController) + + " does not currently support data for the type " + entityType); } } private IEnumerable ExecutePostFilter(IEnumerable entities, string postFilter) { - if (postFilter.IsNullOrWhiteSpace()) return entities; + if (postFilter.IsNullOrWhiteSpace()) + { + return entities; + } var postFilterConditions = postFilter.Split(Constants.CharArrays.Ampersand); foreach (var postFilterCondition in postFilterConditions) { - var queryCondition = BuildQueryCondition(postFilterCondition); + QueryCondition queryCondition = BuildQueryCondition(postFilterCondition); if (queryCondition != null) { - var whereClauseExpression = queryCondition.BuildCondition("x"); + Expression> whereClauseExpression = queryCondition.BuildCondition("x"); entities = entities.Where(whereClauseExpression.Compile()); } - } + return entities; } - private static readonly string[] _postFilterSplitStrings = new[] - { - "=", - "==", - "!=", - "<>", - ">", - "<", - ">=", - "<=" - }; - private static QueryCondition BuildQueryCondition(string postFilter) { var postFilterParts = postFilter.Split(_postFilterSplitStrings, 2, StringSplitOptions.RemoveEmptyEntries); @@ -1234,26 +1262,21 @@ private static QueryCondition BuildQueryCondition(string postFilter) return null; } - var type = typeof(T); - var property = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance); + Type type = typeof(T); + PropertyInfo property = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance); if (property == null) { return null; } - var queryCondition = new QueryCondition() + var queryCondition = new QueryCondition { - Term = new OperatorTerm() - { - Operator = binaryOperator - }, + Term = new OperatorTerm { Operator = binaryOperator }, ConstraintValue = constraintValue, - Property = new PropertyModel() + Property = new PropertyModel { - Alias = propertyName, - Name = propertyName, - Type = property.PropertyType.Name + Alias = propertyName, Name = propertyName, Type = property.PropertyType.Name } }; @@ -1274,14 +1297,141 @@ private EntityBasic MapEntity(object entity, string culture = null) private string ClientCulture() => Request.ClientCulture(); + + #region GetById + + /// + /// Gets an entity by it's id + /// + /// + /// + /// + public ActionResult GetById(int id, UmbracoEntityTypes type) => GetResultForId(id, type); + + /// + /// Gets an entity by it's key + /// + /// + /// + /// + public ActionResult GetById(Guid id, UmbracoEntityTypes type) => GetResultForKey(id, type); + + /// + /// Gets an entity by it's UDI + /// + /// + /// + /// + public ActionResult GetById(Udi id, UmbracoEntityTypes type) + { + var guidUdi = id as GuidUdi; + if (guidUdi != null) + { + return GetResultForKey(guidUdi.Guid, type); + } + + return NotFound(); + } + + #endregion + + #region GetByIds + + /// + /// Get entities by integer ids + /// + /// + /// + /// + /// + /// We allow for POST because there could be quite a lot of Ids + /// + [HttpGet] + [HttpPost] + public ActionResult> GetByIds([FromJsonPath] int[] ids, + [FromQuery] UmbracoEntityTypes type) + { + if (ids == null) + { + return NotFound(); + } + + return new ActionResult>(GetResultForIds(ids, type)); + } + + /// + /// Get entities by GUID ids + /// + /// + /// + /// + /// + /// We allow for POST because there could be quite a lot of Ids + /// + [HttpGet] + [HttpPost] + public ActionResult> GetByIds([FromJsonPath] Guid[] ids, + [FromQuery] UmbracoEntityTypes type) + { + if (ids == null) + { + return NotFound(); + } + + return new ActionResult>(GetResultForKeys(ids, type)); + } + + /// + /// Get entities by UDIs + /// + /// + /// A list of UDIs to lookup items by, all UDIs must be of the same UDI type! + /// + /// + /// + /// + /// We allow for POST because there could be quite a lot of Ids. + /// + [HttpGet] + [HttpPost] + public ActionResult> GetByIds([FromJsonPath] Udi[] ids, + [FromQuery] UmbracoEntityTypes type) + { + if (ids == null) + { + return NotFound(); + } + + if (ids.Length == 0) + { + return Enumerable.Empty().ToList(); + } + + //all udi types will need to be the same in this list so we'll determine by the first + //currently we only support GuidUdi for this method + + var guidUdi = ids[0] as GuidUdi; + if (guidUdi != null) + { + return new ActionResult>( + GetResultForKeys(ids.Select(x => ((GuidUdi)x).Guid).ToArray(), type)); + } + + return NotFound(); + } + + #endregion + #region Methods to get all dictionary items + private IEnumerable GetAllDictionaryItems() { var list = new List(); - foreach (var dictionaryItem in _localizationService.GetRootDictionaryItems().OrderBy(DictionaryItemSort())) + foreach (IDictionaryItem dictionaryItem in _localizationService.GetRootDictionaryItems() + .OrderBy(DictionaryItemSort())) { - var item = _umbracoMapper.Map(dictionaryItem); + EntityBasic item = _umbracoMapper.Map(dictionaryItem); list.Add(item); GetChildItemsForList(dictionaryItem, list); } @@ -1293,15 +1443,16 @@ private IEnumerable GetAllDictionaryItems() private void GetChildItemsForList(IDictionaryItem dictionaryItem, ICollection list) { - foreach (var childItem in _localizationService.GetDictionaryItemChildren(dictionaryItem.Key).OrderBy(DictionaryItemSort())) + foreach (IDictionaryItem childItem in _localizationService.GetDictionaryItemChildren(dictionaryItem.Key) + .OrderBy(DictionaryItemSort())) { - var item = _umbracoMapper.Map(childItem); + EntityBasic item = _umbracoMapper.Map(childItem); list.Add(item); GetChildItemsForList(childItem, list); } } - #endregion + #endregion } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/MemberGroupController.cs b/src/Umbraco.Web.BackOffice/Controllers/MemberGroupController.cs index fb5286505e65..24f128e4104b 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MemberGroupController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MemberGroupController.cs @@ -12,21 +12,20 @@ using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Cms.Web.Common.Authorization; using Umbraco.Extensions; -using Constants = Umbraco.Cms.Core.Constants; namespace Umbraco.Cms.Web.BackOffice.Controllers { /// - /// An API controller used for dealing with member groups + /// An API controller used for dealing with member groups /// [PluginController(Constants.Web.Mvc.BackOfficeApiArea)] [Authorize(Policy = AuthorizationPolicies.TreeAccessMemberGroups)] [ParameterSwapControllerActionSelector(nameof(GetById), "id", typeof(int), typeof(Guid), typeof(Udi))] public class MemberGroupController : UmbracoAuthorizedJsonController { + private readonly ILocalizedTextService _localizedTextService; private readonly IMemberGroupService _memberGroupService; private readonly IUmbracoMapper _umbracoMapper; - private readonly ILocalizedTextService _localizedTextService; public MemberGroupController( IMemberGroupService memberGroupService, @@ -35,11 +34,12 @@ public MemberGroupController( { _memberGroupService = memberGroupService ?? throw new ArgumentNullException(nameof(memberGroupService)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); - _localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); + _localizedTextService = + localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); } /// - /// Gets the member group json for the member group id + /// Gets the member group json for the member group id /// /// /// @@ -56,7 +56,7 @@ public ActionResult GetById(int id) } /// - /// Gets the member group json for the member group guid + /// Gets the member group json for the member group guid /// /// /// @@ -72,7 +72,7 @@ public ActionResult GetById(Guid id) } /// - /// Gets the member group json for the member group udi + /// Gets the member group json for the member group udi /// /// /// @@ -100,7 +100,7 @@ public IEnumerable GetByIds([FromQuery] int[] ids) [HttpPost] public IActionResult DeleteById(int id) { - var memberGroup = _memberGroupService.GetById(id); + IMemberGroup memberGroup = _memberGroupService.GetById(id); if (memberGroup == null) { return NotFound(); @@ -112,7 +112,7 @@ public IActionResult DeleteById(int id) public IEnumerable GetAllGroups() => _memberGroupService.GetAll() - .Select(_umbracoMapper.Map); + .Select(_umbracoMapper.Map); public MemberGroupDisplay GetEmpty() { @@ -120,9 +120,24 @@ public MemberGroupDisplay GetEmpty() return _umbracoMapper.Map(item); } - public ActionResult PostSave(MemberGroupSave saveModel) + public bool IsMemberGroupNameUnique(int id, string oldName, string newName) { + if (newName == oldName) + { + return true; // name hasn't changed + } + + IMemberGroup memberGroup = _memberGroupService.GetByName(newName); + if (memberGroup == null) + { + return true; // no member group found + } + return memberGroup.Id == id; + } + + public ActionResult PostSave(MemberGroupSave saveModel) + { var id = int.Parse(saveModel.Id.ToString(), CultureInfo.InvariantCulture); IMemberGroup memberGroup = id > 0 ? _memberGroupService.GetById(id) : new MemberGroup(); if (memberGroup == null) @@ -130,16 +145,28 @@ public ActionResult PostSave(MemberGroupSave saveModel) return NotFound(); } - memberGroup.Name = saveModel.Name; - _memberGroupService.Save(memberGroup); + if (IsMemberGroupNameUnique(memberGroup.Id, memberGroup.Name, saveModel.Name)) + { + memberGroup.Name = saveModel.Name; + _memberGroupService.Save(memberGroup); - MemberGroupDisplay display = _umbracoMapper.Map(memberGroup); + MemberGroupDisplay display = _umbracoMapper.Map(memberGroup); - display.AddSuccessNotification( - _localizedTextService.Localize("speechBubbles","memberGroupSavedHeader"), - string.Empty); + display.AddSuccessNotification( + _localizedTextService.Localize("speechBubbles", "memberGroupSavedHeader"), + string.Empty); - return display; + return display; + } + else + { + MemberGroupDisplay display = _umbracoMapper.Map(memberGroup); + display.AddErrorNotification( + _localizedTextService.Localize("speechBubbles", "memberGroupNameDuplicate"), + string.Empty); + + return display; + } } } } diff --git a/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs b/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs index 1767386088c0..58a686230028 100644 --- a/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs +++ b/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs @@ -36,7 +36,6 @@ public class ConfigureBackOfficeCookieOptions : IConfigureNamedOptions _optionsSnapshot; /// /// Initializes a new instance of the class. diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs index 19a90746132d..9e5919c1e265 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs @@ -115,7 +115,7 @@ public string LocalTempPath // hopefully it gets a new Guid or new application id? string hashString = SiteName + "::" + ApplicationId; string hash = hashString.GenerateHash(); - string siteTemp = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", hash); + string siteTemp = Path.Combine(Path.GetTempPath(), "UmbracoData", hash); return _localTempPath = siteTemp; diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 00d6103d332c..b282b469a36d 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -1,20453 +1,7 @@ { - "name": "Umbraco.Web.UI.Client", - "lockfileVersion": 2, + "name": "ui", "requires": true, - "packages": { - "": { - "dependencies": { - "@microsoft/signalr": "^3.1.8", - "ace-builds": "1.4.2", - "angular": "1.8.0", - "angular-animate": "1.7.5", - "angular-aria": "1.7.9", - "angular-chart.js": "^1.1.1", - "angular-cookies": "1.7.5", - "angular-dynamic-locale": "0.1.37", - "angular-i18n": "1.7.5", - "angular-local-storage": "0.7.1", - "angular-messages": "1.7.5", - "angular-mocks": "1.7.5", - "angular-route": "1.7.5", - "angular-sanitize": "1.7.5", - "angular-touch": "1.7.5", - "angular-ui-sortable": "0.19.0", - "animejs": "2.2.0", - "bootstrap-social": "5.1.1", - "chart.js": "^2.9.3", - "clipboard": "2.0.4", - "diff": "3.5.0", - "flatpickr": "4.6.9", - "font-awesome": "4.7.0", - "jquery": "^3.5.1", - "jquery-ui-dist": "1.12.1", - "jquery-ui-touch-punch": "0.2.3", - "lazyload-js": "1.0.0", - "moment": "2.22.2", - "ng-file-upload": "12.2.13", - "nouislider": "15.4.0", - "npm": "^6.14.7", - "spectrum-colorpicker2": "2.0.8", - "tinymce": "4.9.11", - "typeahead.js": "0.11.1", - "underscore": "1.12.1", - "wicg-inert": "^3.0.2" - }, - "devDependencies": { - "@babel/core": "7.6.4", - "@babel/plugin-proposal-object-rest-spread": "7.13.8", - "@babel/preset-env": "7.6.3", - "autoprefixer": "9.6.5", - "caniuse-lite": "^1.0.30001237", - "cssnano": "4.1.10", - "fs": "0.0.2", - "gulp": "4.0.2", - "gulp-angular-embed-templates": "^2.3.0", - "gulp-babel": "8.0.0", - "gulp-clean-css": "4.2.0", - "gulp-cli": "^2.3.0", - "gulp-concat": "2.6.1", - "gulp-eslint": "6.0.0", - "gulp-imagemin": "7.1.0", - "gulp-less": "4.0.1", - "gulp-minify": "3.1.0", - "gulp-notify": "^3.0.0", - "gulp-postcss": "8.0.0", - "gulp-rename": "1.4.0", - "gulp-sort": "2.0.0", - "gulp-sourcemaps": "^2.6.5", - "gulp-watch": "5.0.1", - "gulp-wrap": "0.15.0", - "gulp-wrap-js": "0.4.1", - "jasmine-core": "3.5.0", - "jsdom": "16.4.0", - "karma": "4.4.1", - "karma-jasmine": "2.0.1", - "karma-jsdom-launcher": "^8.0.2", - "karma-junit-reporter": "2.0.1", - "karma-spec-reporter": "0.0.32", - "less": "3.10.3", - "lodash": "4.17.21", - "marked": "^0.7.0", - "merge-stream": "2.0.0", - "run-sequence": "2.2.1" - }, - "engines": { - "node": ">=10.00.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", - "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.4.tgz", - "integrity": "sha512-Rm0HGw101GY8FTzpWSyRbki/jzq+/PkNQJ+nSulrdY6gFGOsNseCqD6KHRYe2E+EdzuBdr2pxCp6s4Uk6eJ+XQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.4", - "@babel/helpers": "^7.6.2", - "@babel/parser": "^7.6.4", - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.3", - "@babel/types": "^7.6.3", - "convert-source-map": "^1.1.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", - "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.6", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.15.4.tgz", - "integrity": "sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.15.4.tgz", - "integrity": "sha512-P8o7JP2Mzi0SdC6eWr1zF+AEYvrsZa7GSY1lTayjF5XJhVH0kjLYUZPvTMflP7tBgZoe9gIhTa60QwFpqh/E0Q==", - "dev": true, - "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.15.4.tgz", - "integrity": "sha512-J14f/vq8+hdC2KoWLIQSsGrC9EFBKE4NFts8pfMpymfApds+fPqR30AOUWc4tyr56h9l/GA1Sxv2q3dLZWbQ/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", - "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", - "dev": true, - "dependencies": { - "@babel/helper-get-function-arity": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", - "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", - "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", - "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", - "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz", - "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.15.4", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-simple-access": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.15.7", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", - "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.15.4.tgz", - "integrity": "sha512-v53MxgvMK/HCwckJ1bZrq6dNKlmwlyRNYM6ypaRTdXWGOE2c1/SCa6dL/HimhPulGhZKw9W0QhREM583F/t0vQ==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-wrap-function": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", - "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", - "dev": true, - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", - "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.15.4.tgz", - "integrity": "sha512-BMRLsdh+D1/aap19TycS4eD1qELGrCBJwzaY9IE8LrpJtJb+H7rQkPIdsfgnMtLBA6DJls7X9z93Z4U8h7xw0A==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", - "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.15.4.tgz", - "integrity": "sha512-Y2o+H/hRV5W8QhIfTpRIBwl57y8PrZt6JM3V8FOo5qarjshHItyH5lXlpMfBfmBefOqSCpKZs/6Dxqp0E/U+uw==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", - "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", - "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz", - "integrity": "sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-compilation-targets": "^7.13.8", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.13.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/helper-compilation-targets": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", - "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/@babel/plugin-transform-parameters": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.15.4.tgz", - "integrity": "sha512-9WB/GUTO6lvJU3XQsSr6J/WKvBC2hcs4Pew8YxZagi6GkTdniyqp8On5kqdK8MN0LMeu0mGbhPN+O049NV/9FQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.6.3.tgz", - "integrity": "sha512-CWQkn7EVnwzlOdR5NOm2+pfgSNEZmvGjOhlCHBDq0J8/EStr+G+FvPEiz9B56dR6MoiUFjXhfE4hjLoAKKJtIQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.2.0", - "@babel/plugin-proposal-dynamic-import": "^7.5.0", - "@babel/plugin-proposal-json-strings": "^7.2.0", - "@babel/plugin-proposal-object-rest-spread": "^7.6.2", - "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.6.2", - "@babel/plugin-syntax-async-generators": "^7.2.0", - "@babel/plugin-syntax-dynamic-import": "^7.2.0", - "@babel/plugin-syntax-json-strings": "^7.2.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", - "@babel/plugin-transform-arrow-functions": "^7.2.0", - "@babel/plugin-transform-async-to-generator": "^7.5.0", - "@babel/plugin-transform-block-scoped-functions": "^7.2.0", - "@babel/plugin-transform-block-scoping": "^7.6.3", - "@babel/plugin-transform-classes": "^7.5.5", - "@babel/plugin-transform-computed-properties": "^7.2.0", - "@babel/plugin-transform-destructuring": "^7.6.0", - "@babel/plugin-transform-dotall-regex": "^7.6.2", - "@babel/plugin-transform-duplicate-keys": "^7.5.0", - "@babel/plugin-transform-exponentiation-operator": "^7.2.0", - "@babel/plugin-transform-for-of": "^7.4.4", - "@babel/plugin-transform-function-name": "^7.4.4", - "@babel/plugin-transform-literals": "^7.2.0", - "@babel/plugin-transform-member-expression-literals": "^7.2.0", - "@babel/plugin-transform-modules-amd": "^7.5.0", - "@babel/plugin-transform-modules-commonjs": "^7.6.0", - "@babel/plugin-transform-modules-systemjs": "^7.5.0", - "@babel/plugin-transform-modules-umd": "^7.2.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.6.3", - "@babel/plugin-transform-new-target": "^7.4.4", - "@babel/plugin-transform-object-super": "^7.5.5", - "@babel/plugin-transform-parameters": "^7.4.4", - "@babel/plugin-transform-property-literals": "^7.2.0", - "@babel/plugin-transform-regenerator": "^7.4.5", - "@babel/plugin-transform-reserved-words": "^7.2.0", - "@babel/plugin-transform-shorthand-properties": "^7.2.0", - "@babel/plugin-transform-spread": "^7.6.2", - "@babel/plugin-transform-sticky-regex": "^7.2.0", - "@babel/plugin-transform-template-literals": "^7.4.4", - "@babel/plugin-transform-typeof-symbol": "^7.2.0", - "@babel/plugin-transform-unicode-regex": "^7.6.2", - "@babel/types": "^7.6.3", - "browserslist": "^4.6.0", - "core-js-compat": "^3.1.1", - "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", - "semver": "^5.5.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.8.tgz", - "integrity": "sha512-2Z5F2R2ibINTc63mY7FLqGfEbmofrHU9FitJW1Q7aPaKFhiPvSq6QEt/BoWN5oME3GVyjcRuNNSRbb9LC0CSWA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.15.4", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz", - "integrity": "sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz", - "integrity": "sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz", - "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz", - "integrity": "sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-unicode-property-regex/node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", - "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "regexpu-core": "^4.7.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz", - "integrity": "sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz", - "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz", - "integrity": "sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz", - "integrity": "sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-classes": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.15.4.tgz", - "integrity": "sha512-Yjvhex8GzBmmPQUvpXRPWQ9WnxXgAFuZSrqOK/eJlOGIXwvv8H3UEdUigl1gb/bnjTrln+e8bkZUYCBt/xYlBg==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz", - "integrity": "sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-destructuring": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz", - "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz", - "integrity": "sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-dotall-regex/node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", - "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "regexpu-core": "^4.7.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz", - "integrity": "sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz", - "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", - "dev": true, - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-for-of": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.15.4.tgz", - "integrity": "sha512-DRTY9fA751AFBDh2oxydvVm4SYevs5ILTWLs6xKXps4Re/KG5nfUkr+TdHCrRWB8C69TlzVgA9b3RmGWmgN9LA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-function-name": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz", - "integrity": "sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz", - "integrity": "sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz", - "integrity": "sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz", - "integrity": "sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.4.tgz", - "integrity": "sha512-qg4DPhwG8hKp4BbVDvX1s8cohM8a6Bvptu4l6Iingq5rW+yRUAhe/YRup/YcW2zCOlrysEWVhftIcKzrEZv3sA==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-simple-access": "^7.15.4", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.15.4.tgz", - "integrity": "sha512-fJUnlQrl/mezMneR72CKCgtOoahqGJNVKpompKwzv3BrEXdlPspTcyxrZ1XmDTIr9PpULrgEQo3qNKp6dW7ssw==", - "dev": true, - "dependencies": { - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.4", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.9", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz", - "integrity": "sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz", - "integrity": "sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-named-capturing-groups-regex/node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", - "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "regexpu-core": "^4.7.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-new-target": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz", - "integrity": "sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-object-super": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz", - "integrity": "sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-parameters": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.15.4.tgz", - "integrity": "sha512-9WB/GUTO6lvJU3XQsSr6J/WKvBC2hcs4Pew8YxZagi6GkTdniyqp8On5kqdK8MN0LMeu0mGbhPN+O049NV/9FQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-property-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz", - "integrity": "sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-regenerator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz", - "integrity": "sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==", - "dev": true, - "dependencies": { - "regenerator-transform": "^0.14.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz", - "integrity": "sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz", - "integrity": "sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-spread": { - "version": "7.15.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.15.8.tgz", - "integrity": "sha512-/daZ8s2tNaRekl9YJa9X4bzjpeRZLt122cpgFnQPLGUe61PH8zMEBmYqKkW5xF5JUEh5buEGXJoQpqBmIbpmEQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz", - "integrity": "sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-template-literals": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz", - "integrity": "sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz", - "integrity": "sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz", - "integrity": "sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.14.5", - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/plugin-transform-unicode-regex/node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", - "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.14.5", - "regexpu-core": "^4.7.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", - "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", - "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", - "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", - "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.9", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@gulp-sourcemaps/identity-map": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz", - "integrity": "sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ==", - "dev": true, - "dependencies": { - "acorn": "^5.0.3", - "css": "^2.2.1", - "normalize-path": "^2.1.1", - "source-map": "^0.6.0", - "through2": "^2.0.3" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/@gulp-sourcemaps/identity-map/node_modules/acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/@gulp-sourcemaps/identity-map/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@gulp-sourcemaps/identity-map/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@gulp-sourcemaps/map-sources": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz", - "integrity": "sha1-iQrnxdjId/bThIYCFazp1+yUW9o=", - "dev": true, - "dependencies": { - "normalize-path": "^2.0.1", - "through2": "^2.0.3" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/@gulp-sourcemaps/map-sources/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@microsoft/signalr": { - "version": "3.1.20", - "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-3.1.20.tgz", - "integrity": "sha512-K9Ivqd+9vDm4vZlx7dXvpAZ3hPAOdCXkZw+QrelHgPHOdIcF2K6Z6XsskxQZfaUz2aLloaifCQNGzc6VTnsyhA==", - "dependencies": { - "eventsource": "^1.0.7", - "request": "^2.88.0", - "ws": "^6.0.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sindresorhus/is": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", - "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@types/angular": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@types/angular/-/angular-1.8.3.tgz", - "integrity": "sha512-vgc5Z+TD07DT7NEUjFm6XMp0kEbGXIa95XmOL5IiHXR9LdrJpcdDh3jl1nCuZbWyzFn5/1OqtMfomcnA1sUFXQ==" - }, - "node_modules/@types/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", - "dev": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "16.11.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.0.tgz", - "integrity": "sha512-8MLkBIYQMuhRBQzGN9875bYsOhPnf/0rgXGo66S2FemHkhbn9qtsz9ywV1iCG+vbjigE4WUNVvw37Dx+L0qsPg==", - "dev": true - }, - "node_modules/@types/q": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", - "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==", - "dev": true - }, - "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dev": true, - "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accord": { - "version": "0.29.0", - "resolved": "https://registry.npmjs.org/accord/-/accord-0.29.0.tgz", - "integrity": "sha512-3OOR92FTc2p5/EcOzPcXp+Cbo+3C15nV9RXHlOUBCBpHhcB+0frbSNR9ehED/o7sTcyGVtqGJpguToEdlXhD0w==", - "dev": true, - "dependencies": { - "convert-source-map": "^1.5.0", - "glob": "^7.0.5", - "indx": "^0.2.3", - "lodash.clone": "^4.3.2", - "lodash.defaults": "^4.0.1", - "lodash.flatten": "^4.2.0", - "lodash.merge": "^4.4.0", - "lodash.partialright": "^4.1.4", - "lodash.pick": "^4.2.1", - "lodash.uniq": "^4.3.0", - "resolve": "^1.5.0", - "semver": "^5.3.0", - "uglify-js": "^2.8.22", - "when": "^3.7.8" - } - }, - "node_modules/ace-builds": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.2.tgz", - "integrity": "sha512-M1JtZctO2Zg+1qeGUFZXtYKsyaRptqQtqpVzlj80I0NzGW9MF3um0DBuizIvQlrPYUlTdm+wcOPZpZoerkxQdA==" - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/after": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", - "dev": true - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/align-text/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", - "dev": true - }, - "node_modules/amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true, - "engines": { - "node": ">=0.4.2" - } - }, - "node_modules/angular": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/angular/-/angular-1.8.0.tgz", - "integrity": "sha512-VdaMx+Qk0Skla7B5gw77a8hzlcOakwF8mjlW13DpIWIDlfqwAbSSLfd8N/qZnzEmQF4jC4iofInd3gE7vL8ZZg==" - }, - "node_modules/angular-animate": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/angular-animate/-/angular-animate-1.7.5.tgz", - "integrity": "sha512-kU/fHIGf2a4a3bH7E1tzALTHk+QfoUSCK9fEcMFisd6ZWvNDwPzXWAilItqOC3EDiAXPmGHaNc9/aXiD9xrAxQ==" - }, - "node_modules/angular-aria": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/angular-aria/-/angular-aria-1.7.9.tgz", - "integrity": "sha512-luI3Jemd1AbOQW0krdzfEG3fM0IFtLY0bSSqIDEx3POE0XjKIC1MkrO8Csyq9PPgueLphyAPofzUwZ8YeZ88SA==" - }, - "node_modules/angular-chart.js": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/angular-chart.js/-/angular-chart.js-1.1.1.tgz", - "integrity": "sha1-SfDhjQgXYrbUyXkeSHr/L7sw9a4=", - "dependencies": { - "angular": "1.x", - "chart.js": "2.3.x" - } - }, - "node_modules/angular-chart.js/node_modules/chart.js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.3.0.tgz", - "integrity": "sha1-QEYOSOLEF8BfwzJc2E97AA3H19Y=", - "dependencies": { - "chartjs-color": "^2.0.0", - "moment": "^2.10.6" - } - }, - "node_modules/angular-cookies": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/angular-cookies/-/angular-cookies-1.7.5.tgz", - "integrity": "sha512-/8xvvSl/Z9Vwu8ChRm+OQE3vmli8Icwl8uTYkHqD7j7cknJP9kNaf7SgsENlsLVtOqLE/I7TCFYrSx3bmSeNQA==" - }, - "node_modules/angular-dynamic-locale": { - "version": "0.1.37", - "resolved": "https://registry.npmjs.org/angular-dynamic-locale/-/angular-dynamic-locale-0.1.37.tgz", - "integrity": "sha512-m5Kyk8W8/mOZSqRxuByOwHBjv8labLBAgvl0Z3iQx2xT/tWCqb94imKUPwumudszdPDjxeopwyucQvm8Sw7ogw==", - "dependencies": { - "@types/angular": "^1.6.25" - } - }, - "node_modules/angular-i18n": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/angular-i18n/-/angular-i18n-1.7.5.tgz", - "integrity": "sha512-52+Jpt8HRJV2bqSbSU6fWkwOvGzj/DxbNpKXxnTuCS9heuJrlm77BS/lhrF4BA8+Uudnh7npr5/yRELobP+8Yw==" - }, - "node_modules/angular-local-storage": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/angular-local-storage/-/angular-local-storage-0.7.1.tgz", - "integrity": "sha1-+9JzB2PCn6mvVyXgGGx4BiHozdI=" - }, - "node_modules/angular-messages": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/angular-messages/-/angular-messages-1.7.5.tgz", - "integrity": "sha512-YDpJpFLyrIgZjE/sIAjgww1y6r3QqXBJbNDI0QjftD37vHXLkwvAOo3A4bxPw8BikyGLcJrFrgf6hRAzntJIWA==" - }, - "node_modules/angular-mocks": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.7.5.tgz", - "integrity": "sha512-I+Ue2Bkx6R9W5178DYrNvzjIdGh4wKKoCWsgz8dc7ysH4mA70Q3M9v5xRF0RUu7r+2CZj+nDeUecvh2paxcYvg==" - }, - "node_modules/angular-route": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/angular-route/-/angular-route-1.7.5.tgz", - "integrity": "sha512-7KfyEVVOWTI+jTY/j5rUNCIHGRyeCOx7YqZI/Ci3IbDK7GIsy6xH+hS5ai0Xi0sLjzDZ0PUDO4gBn+K0dVtlOg==" - }, - "node_modules/angular-sanitize": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/angular-sanitize/-/angular-sanitize-1.7.5.tgz", - "integrity": "sha512-wjKCJOIwrkEvfD0keTnKGi6We13gtoCAQIHcdoqyoo3gwvcgNfYymVQIS3+iCGVcjfWz0jHuS3KgB4ysRWsTTA==" - }, - "node_modules/angular-touch": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/angular-touch/-/angular-touch-1.7.5.tgz", - "integrity": "sha512-XNAZNG0RA1mtdwBJheViCF1H/7wOygp4MLIfs5y1K+rne6AeaYKZcV6EJs9fvgfLKLO6ecm1+3J8hoCkdhhxQw==" - }, - "node_modules/angular-ui-sortable": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/angular-ui-sortable/-/angular-ui-sortable-0.19.0.tgz", - "integrity": "sha512-u/uc981Nzg4XN1bMU9qKleMTSt7F1XjMWnyGw6gxPLIeQeLZm8jWNy7tj8y2r2HmvzXFbQVq2z6rObznFKAekQ==", - "dependencies": { - "angular": ">=1.2.x", - "jquery": ">=3.1.x", - "jquery-ui-dist": ">=1.12.x" - } - }, - "node_modules/animejs": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/animejs/-/animejs-2.2.0.tgz", - "integrity": "sha1-Ne79/FNbgZScnLBvCz5gwC5v3IA=" - }, - "node_modules/ansi-colors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", - "dev": true, - "dependencies": { - "ansi-wrap": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-cyan": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", - "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", - "dev": true, - "dependencies": { - "ansi-wrap": "0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", - "dev": true, - "dependencies": { - "ansi-wrap": "0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-red": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", - "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", - "dev": true, - "dependencies": { - "ansi-wrap": "0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "node_modules/anymatch/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/append-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", - "dev": true, - "dependencies": { - "buffer-equal": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/archive-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz", - "integrity": "sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA=", - "dev": true, - "optional": true, - "dependencies": { - "file-type": "^4.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/archive-type/node_modules/file-type": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", - "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" - }, - "node_modules/argh": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/argh/-/argh-0.1.4.tgz", - "integrity": "sha1-PrTWEpc/xrbcbvM49W91nyrFw6Y=", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-filter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", - "dev": true, - "dependencies": { - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", - "dev": true, - "dependencies": { - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-initial": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", - "dev": true, - "dependencies": { - "array-slice": "^1.0.0", - "is-number": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-initial/node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-last": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", - "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", - "dev": true, - "dependencies": { - "is-number": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-last/node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-sort": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", - "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", - "dev": true, - "dependencies": { - "default-compare": "^1.0.0", - "get-value": "^2.0.6", - "kind-of": "^5.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arraybuffer.slice": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", - "dev": true - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true, - "optional": true - }, - "node_modules/asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/async-done": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", - "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.2", - "process-nextick-args": "^2.0.0", - "stream-exhaust": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, - "node_modules/async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, - "node_modules/async-settle": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", - "dev": true, - "dependencies": { - "async-done": "^1.2.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true, - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/autoprefixer": { - "version": "9.6.5", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.5.tgz", - "integrity": "sha512-rGd50YV8LgwFQ2WQp4XzOTG69u1qQsXn0amww7tjqV5jJuNazgFKYEVItEBngyyvVITKOg20zr2V+9VsrXJQ2g==", - "dev": true, - "dependencies": { - "browserslist": "^4.7.0", - "caniuse-lite": "^1.0.30000999", - "chalk": "^2.4.2", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "postcss": "^7.0.18", - "postcss-value-parser": "^4.0.2" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" - }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "dependencies": { - "object.assign": "^4.1.0" - } - }, - "node_modules/bach": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", - "dev": true, - "dependencies": { - "arr-filter": "^1.1.1", - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "array-each": "^1.0.0", - "array-initial": "^1.0.0", - "array-last": "^1.1.1", - "async-done": "^1.2.2", - "async-settle": "^1.0.0", - "now-and-later": "^2.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base64-arraybuffer": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", - "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/base64id": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", - "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/better-assert": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", - "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", - "dev": true, - "dependencies": { - "callsite": "1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/bin-build": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bin-build/-/bin-build-3.0.0.tgz", - "integrity": "sha512-jcUOof71/TNAI2uM5uoUaDq2ePcVBQ3R/qhxAz1rX7UfvduAL/RXD3jXzvn8cVcDJdGVkiR1shal3OH0ImpuhA==", - "dev": true, - "optional": true, - "dependencies": { - "decompress": "^4.0.0", - "download": "^6.2.2", - "execa": "^0.7.0", - "p-map-series": "^1.0.0", - "tempfile": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-build/node_modules/cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "optional": true, - "dependencies": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "node_modules/bin-build/node_modules/execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "optional": true, - "dependencies": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-build/node_modules/get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-check": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz", - "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==", - "dev": true, - "optional": true, - "dependencies": { - "execa": "^0.7.0", - "executable": "^4.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-check/node_modules/cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "optional": true, - "dependencies": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "node_modules/bin-check/node_modules/execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "optional": true, - "dependencies": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-check/node_modules/get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-version": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-3.1.0.tgz", - "integrity": "sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ==", - "dev": true, - "optional": true, - "dependencies": { - "execa": "^1.0.0", - "find-versions": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/bin-version-check": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-4.0.0.tgz", - "integrity": "sha512-sR631OrhC+1f8Cvs8WyVWOA33Y8tgwjETNPyyD/myRBXLkfS/vl74FmH/lFcRl9KY3zwGh7jFhvyk9vV3/3ilQ==", - "dev": true, - "optional": true, - "dependencies": { - "bin-version": "^3.0.0", - "semver": "^5.6.0", - "semver-truncate": "^1.1.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/bin-wrapper": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bin-wrapper/-/bin-wrapper-4.1.0.tgz", - "integrity": "sha512-hfRmo7hWIXPkbpi0ZltboCMVrU+0ClXR/JgbCKKjlDjQf6igXa7OwdqNcFWQZPZTgiY7ZpzE3+LjjkLiTN2T7Q==", - "dev": true, - "optional": true, - "dependencies": { - "bin-check": "^4.1.0", - "bin-version-check": "^4.0.0", - "download": "^7.1.0", - "import-lazy": "^3.1.0", - "os-filter-obj": "^2.0.0", - "pify": "^4.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/bin-wrapper/node_modules/download": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/download/-/download-7.1.0.tgz", - "integrity": "sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ==", - "dev": true, - "optional": true, - "dependencies": { - "archive-type": "^4.0.0", - "caw": "^2.0.1", - "content-disposition": "^0.5.2", - "decompress": "^4.2.0", - "ext-name": "^5.0.0", - "file-type": "^8.1.0", - "filenamify": "^2.0.0", - "get-stream": "^3.0.0", - "got": "^8.3.1", - "make-dir": "^1.2.0", - "p-event": "^2.1.0", - "pify": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/bin-wrapper/node_modules/download/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-wrapper/node_modules/file-type": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz", - "integrity": "sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/bin-wrapper/node_modules/get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-wrapper/node_modules/got": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", - "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", - "dev": true, - "optional": true, - "dependencies": { - "@sindresorhus/is": "^0.7.0", - "cacheable-request": "^2.1.1", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "into-stream": "^3.1.0", - "is-retry-allowed": "^1.1.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "mimic-response": "^1.0.0", - "p-cancelable": "^0.4.0", - "p-timeout": "^2.0.1", - "pify": "^3.0.0", - "safe-buffer": "^5.1.1", - "timed-out": "^4.0.1", - "url-parse-lax": "^3.0.0", - "url-to-options": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-wrapper/node_modules/got/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-wrapper/node_modules/make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dev": true, - "optional": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-wrapper/node_modules/make-dir/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-wrapper/node_modules/p-cancelable": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", - "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-wrapper/node_modules/p-event": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-2.3.1.tgz", - "integrity": "sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA==", - "dev": true, - "optional": true, - "dependencies": { - "p-timeout": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/bin-wrapper/node_modules/p-timeout": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", - "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", - "dev": true, - "optional": true, - "dependencies": { - "p-finally": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-wrapper/node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-wrapper/node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "optional": true, - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "optional": true, - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/bl": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", - "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", - "dev": true, - "optional": true, - "dependencies": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/blob": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", - "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", - "dev": true - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "node_modules/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "dev": true, - "dependencies": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "node_modules/bootstrap": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", - "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/bootstrap-social": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/bootstrap-social/-/bootstrap-social-5.1.1.tgz", - "integrity": "sha1-dTDGeK31bPj60/qCwp1NPl0CdQE=", - "dependencies": { - "bootstrap": "~3", - "font-awesome": "~4.7" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "node_modules/browserslist": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.4.tgz", - "integrity": "sha512-Zg7RpbZpIJRW3am9Lyckue7PLytvVxxhJj1CaJVlCWENsGEAOlnlt8X0ZxGRPp7Bt9o8tIRM5SEXy4BCPMJjLQ==", - "dev": true, - "dependencies": { - "caniuse-lite": "^1.0.30001265", - "electron-to-chromium": "^1.3.867", - "escalade": "^3.1.1", - "node-releases": "^2.0.0", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "dev": true, - "dependencies": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "node_modules/buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "dev": true - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true, - "optional": true, - "engines": { - "node": "*" - } - }, - "node_modules/buffer-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", - "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", - "dev": true - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/bufferstreams": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bufferstreams/-/bufferstreams-1.0.1.tgz", - "integrity": "sha1-z7GtlWjTujz+k1upq92VLeiKqyo=", - "dev": true, - "dependencies": { - "readable-stream": "^1.0.33" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/bufferstreams/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "node_modules/bufferstreams/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/bufferstreams/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, - "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cacheable-request": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", - "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", - "dev": true, - "optional": true, - "dependencies": { - "clone-response": "1.0.2", - "get-stream": "3.0.0", - "http-cache-semantics": "3.8.1", - "keyv": "3.0.0", - "lowercase-keys": "1.0.0", - "normalize-url": "2.0.1", - "responselike": "1.0.2" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", - "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cacheable-request/node_modules/normalize-url": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", - "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", - "dev": true, - "optional": true, - "dependencies": { - "prepend-http": "^2.0.0", - "query-string": "^5.0.1", - "sort-keys": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cacheable-request/node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/cacheable-request/node_modules/sort-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", - "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", - "dev": true, - "optional": true, - "dependencies": { - "is-plain-obj": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "dependencies": { - "callsites": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "dependencies": { - "caller-callsite": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", - "dev": true, - "optional": true, - "dependencies": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001267", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001267.tgz", - "integrity": "sha512-r1mjTzAuJ9W8cPBGbbus8E0SKcUP7gn03R14Wk8FlAlqhH9hroy9nLqmpuXlfKEw/oILW+FGz47ipXV2O7x8lg==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "node_modules/caw": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", - "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", - "dev": true, - "optional": true, - "dependencies": { - "get-proxy": "^2.0.0", - "isurl": "^1.0.0-alpha5", - "tunnel-agent": "^0.6.0", - "url-to-options": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "dev": true, - "dependencies": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "node_modules/chart.js": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz", - "integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==", - "dependencies": { - "chartjs-color": "^2.1.0", - "moment": "^2.10.2" - } - }, - "node_modules/chartjs-color": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz", - "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==", - "dependencies": { - "chartjs-color-string": "^0.6.0", - "color-convert": "^1.9.3" - } - }, - "node_modules/chartjs-color-string": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", - "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", - "dependencies": { - "color-name": "^1.0.0" - } - }, - "node_modules/chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", - "dev": true, - "dependencies": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "optionalDependencies": { - "fsevents": "^1.2.7" - } - }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/clean-css": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", - "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", - "dev": true, - "dependencies": { - "source-map": "~0.6.0" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/clean-css/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cli-color": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", - "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.1.1", - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.14", - "timers-ext": "^0.1.5" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/clipboard": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz", - "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==", - "dependencies": { - "good-listener": "^1.2.2", - "select": "^1.1.2", - "tiny-emitter": "^2.0.0" - } - }, - "node_modules/cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "dev": true, - "dependencies": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - } - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "dev": true, - "optional": true, - "dependencies": { - "mimic-response": "^1.0.0" - } - }, - "node_modules/clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", - "dev": true - }, - "node_modules/cloneable-readable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", - "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" - } - }, - "node_modules/coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "dev": true, - "dependencies": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/collection-map": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", - "dev": true, - "dependencies": { - "arr-map": "^2.0.2", - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", - "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-convert/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-string": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.6.0.tgz", - "integrity": "sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==", - "dev": true, - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/colornames": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", - "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=", - "dev": true - }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/colorspace": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", - "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", - "dev": true, - "dependencies": { - "color": "3.0.x", - "text-hex": "1.0.x" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/component-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", - "dev": true - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "node_modules/component-inherit": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/concat-with-sourcemaps": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", - "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", - "dev": true, - "dependencies": { - "source-map": "^0.6.1" - } - }, - "node_modules/concat-with-sourcemaps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/connect/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/connect/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/console-stream": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/console-stream/-/console-stream-0.1.1.tgz", - "integrity": "sha1-oJX+B7IEZZVfL6/Si11yvM2UnUQ=", - "dev": true, - "optional": true - }, - "node_modules/consolidate": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", - "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", - "dev": true, - "dependencies": { - "bluebird": "^3.1.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "dev": true, - "optional": true, - "dependencies": { - "safe-buffer": "5.1.2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/copy-props": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz", - "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==", - "dev": true, - "dependencies": { - "each-props": "^1.3.2", - "is-plain-object": "^5.0.0" - } - }, - "node_modules/core-js-compat": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.18.3.tgz", - "integrity": "sha512-4zP6/y0a2RTHN5bRGT7PTq9lVt3WzvffTNjqnTKsXhkAYNDTkdCLOIfAdOLcQ/7TDdyRj3c+NeHe1NmF1eDScw==", - "dev": true, - "dependencies": { - "browserslist": "^4.17.3", - "semver": "7.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-js-compat/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "node_modules/cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dev": true, - "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/css": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", - "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "source-map": "^0.6.1", - "source-map-resolve": "^0.5.2", - "urix": "^0.1.0" - } - }, - "node_modules/css-color-names": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/css-declaration-sorter": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.1", - "timsort": "^0.3.0" - }, - "engines": { - "node": ">4" - } - }, - "node_modules/css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "node_modules/css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", - "dev": true - }, - "node_modules/css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/css-tree/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cssnano": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", - "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", - "dev": true, - "dependencies": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.7", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-preset-default": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", - "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", - "dev": true, - "dependencies": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.1", - "postcss-colormin": "^4.0.3", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.2", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.11", - "postcss-merge-rules": "^4.0.3", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.2", - "postcss-minify-params": "^4.0.2", - "postcss-minify-selectors": "^4.0.2", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.2", - "postcss-normalize-positions": "^4.0.2", - "postcss-normalize-repeat-style": "^4.0.2", - "postcss-normalize-string": "^4.0.2", - "postcss-normalize-timing-functions": "^4.0.2", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.2", - "postcss-ordered-values": "^4.1.2", - "postcss-reduce-initial": "^4.0.3", - "postcss-reduce-transforms": "^4.0.2", - "postcss-svgo": "^4.0.3", - "postcss-unique-selectors": "^4.0.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-util-get-arguments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", - "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-util-get-match": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", - "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-util-raw-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-util-same-parent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "dev": true, - "dependencies": { - "css-tree": "^1.1.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/csso/node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, - "node_modules/csso/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "dev": true, - "optional": true, - "dependencies": { - "array-find-index": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", - "dev": true - }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/date-format": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", - "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/debug-fabulous": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz", - "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==", - "dev": true, - "dependencies": { - "debug": "3.X", - "memoizee": "0.4.X", - "object-assign": "4.X" - } - }, - "node_modules/debug-fabulous/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, - "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/decompress": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz", - "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==", - "dev": true, - "optional": true, - "dependencies": { - "decompress-tar": "^4.0.0", - "decompress-tarbz2": "^4.0.0", - "decompress-targz": "^4.0.0", - "decompress-unzip": "^4.0.1", - "graceful-fs": "^4.1.10", - "make-dir": "^1.0.0", - "pify": "^2.3.0", - "strip-dirs": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "dev": true, - "optional": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-tar": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", - "dev": true, - "optional": true, - "dependencies": { - "file-type": "^5.2.0", - "is-stream": "^1.1.0", - "tar-stream": "^1.5.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-tar/node_modules/file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-tarbz2": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", - "dev": true, - "optional": true, - "dependencies": { - "decompress-tar": "^4.1.0", - "file-type": "^6.1.0", - "is-stream": "^1.1.0", - "seek-bzip": "^1.0.5", - "unbzip2-stream": "^1.0.9" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-tarbz2/node_modules/file-type": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-targz": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", - "dev": true, - "optional": true, - "dependencies": { - "decompress-tar": "^4.1.1", - "file-type": "^5.2.0", - "is-stream": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-targz/node_modules/file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-unzip": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", - "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", - "dev": true, - "optional": true, - "dependencies": { - "file-type": "^3.8.0", - "get-stream": "^2.2.0", - "pify": "^2.3.0", - "yauzl": "^2.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress-unzip/node_modules/file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decompress-unzip/node_modules/get-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", - "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", - "dev": true, - "optional": true, - "dependencies": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decompress-unzip/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decompress/node_modules/make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dev": true, - "optional": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress/node_modules/make-dir/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/decompress/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/default-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", - "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", - "dev": true, - "dependencies": { - "kind-of": "^5.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-resolution": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegate": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", - "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" - }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", - "dev": true - }, - "node_modules/diagnostics": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", - "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", - "dev": true, - "dependencies": { - "colorspace": "1.1.x", - "enabled": "1.0.x", - "kuler": "1.0.x" - } - }, - "node_modules/diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-serialize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", - "dev": true, - "dependencies": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" - } - }, - "node_modules/dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - } - }, - "node_modules/dom-serializer/node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/dom-serializer/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true - }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "dependencies": { - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "dev": true, - "dependencies": { - "domelementtype": "1" - } - }, - "node_modules/domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "dev": true, - "dependencies": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/download": { - "version": "6.2.5", - "resolved": "https://registry.npmjs.org/download/-/download-6.2.5.tgz", - "integrity": "sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA==", - "dev": true, - "optional": true, - "dependencies": { - "caw": "^2.0.0", - "content-disposition": "^0.5.2", - "decompress": "^4.0.0", - "ext-name": "^5.0.0", - "file-type": "5.2.0", - "filenamify": "^2.0.0", - "get-stream": "^3.0.0", - "got": "^7.0.0", - "make-dir": "^1.0.0", - "p-event": "^1.0.0", - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/download/node_modules/file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/download/node_modules/get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/download/node_modules/make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dev": true, - "optional": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/download/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", - "dev": true, - "dependencies": { - "readable-stream": "~1.1.9" - } - }, - "node_modules/duplexer2/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "node_modules/duplexer2/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/duplexer2/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, - "node_modules/duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true, - "optional": true - }, - "node_modules/duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "node_modules/each-props": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", - "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.1", - "object.defaults": "^1.1.0" - } - }, - "node_modules/each-props/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "node_modules/electron-to-chromium": { - "version": "1.3.870", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.870.tgz", - "integrity": "sha512-PiJMshfq6PL+i1V+nKLwhHbCKeD8eAz8rvO9Cwk/7cChOHJBtufmjajLyYLsSRHguRFiOCVx3XzJLeZsIAYfSA==", - "dev": true - }, - "node_modules/emits": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emits/-/emits-3.0.0.tgz", - "integrity": "sha1-MnUrupXhcHshlWI4Srm7ix/WL3A=", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/enabled": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", - "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", - "dev": true, - "dependencies": { - "env-variable": "0.0.x" - } - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/engine.io": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", - "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", - "dev": true, - "dependencies": { - "accepts": "~1.3.4", - "base64id": "1.0.0", - "cookie": "0.3.1", - "debug": "~3.1.0", - "engine.io-parser": "~2.1.0", - "ws": "~3.3.1" - } - }, - "node_modules/engine.io-client": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", - "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", - "dev": true, - "dependencies": { - "component-emitter": "1.2.1", - "component-inherit": "0.0.3", - "debug": "~3.1.0", - "engine.io-parser": "~2.1.1", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "ws": "~3.3.1", - "xmlhttprequest-ssl": "~1.5.4", - "yeast": "0.1.2" - } - }, - "node_modules/engine.io-client/node_modules/component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true - }, - "node_modules/engine.io-client/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/engine.io-client/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/engine.io-client/node_modules/ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "dev": true, - "dependencies": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - }, - "node_modules/engine.io-parser": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", - "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", - "dev": true, - "dependencies": { - "after": "0.8.2", - "arraybuffer.slice": "~0.0.7", - "base64-arraybuffer": "0.1.5", - "blob": "0.0.5", - "has-binary2": "~1.0.2" - } - }, - "node_modules/engine.io/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/engine.io/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/engine.io/node_modules/ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "dev": true, - "dependencies": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - }, - "node_modules/ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", - "dev": true - }, - "node_modules/entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - }, - "node_modules/env-variable": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.6.tgz", - "integrity": "sha512-bHz59NlBbtS0NhftmR8+ExBEekE7br0e01jw+kk0NDro7TtZzBYZ5ScGPs3OmwnpyfHTHOtr1Y6uedCdrIldtg==", - "dev": true - }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "dev": true, - "optional": true, - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "dev": true, - "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "node_modules/es5-ext/node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", - "dev": true - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=4.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", - "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.3", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.2", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.3", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "dependencies": { - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/espree": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", - "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estemplate": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/estemplate/-/estemplate-0.5.1.tgz", - "integrity": "sha1-FxSp1GGQc4rJWLyv1J4CnNpWo54=", - "dev": true, - "dependencies": { - "esprima": "^2.7.2", - "estraverse": "^4.1.1" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/eventsource": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", - "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", - "dependencies": { - "original": "^1.0.0" - }, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/exec-buffer": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/exec-buffer/-/exec-buffer-3.2.0.tgz", - "integrity": "sha512-wsiD+2Tp6BWHoVv3B+5Dcx6E7u5zky+hUwOHjuH2hKSLR3dvRmX8fk8UD8uqQixHs4Wk6eDmiegVrMPjKj7wpA==", - "dev": true, - "optional": true, - "dependencies": { - "execa": "^0.7.0", - "p-finally": "^1.0.0", - "pify": "^3.0.0", - "rimraf": "^2.5.4", - "tempfile": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/exec-buffer/node_modules/cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "optional": true, - "dependencies": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "node_modules/exec-buffer/node_modules/execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "optional": true, - "dependencies": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/exec-buffer/node_modules/get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/exec-buffer/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "optional": true, - "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/executable": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", - "dev": true, - "optional": true, - "dependencies": { - "pify": "^2.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/executable/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "dev": true, - "dependencies": { - "fill-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-range/node_modules/fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", - "dev": true, - "dependencies": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-range/node_modules/is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-range/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-range/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ext": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", - "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", - "dev": true, - "dependencies": { - "type": "^2.5.0" - } - }, - "node_modules/ext-list": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", - "dev": true, - "optional": true, - "dependencies": { - "mime-db": "^1.28.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ext-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", - "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", - "dev": true, - "optional": true, - "dependencies": { - "ext-list": "^2.0.0", - "sort-keys-length": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ext/node_modules/type": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", - "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==", - "dev": true - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fancy-log": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", - "dev": true, - "dependencies": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "parse-node-version": "^1.0.0", - "time-stamp": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-glob/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-glob/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-glob/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/fast-glob/node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/fast-glob/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fast-xml-parser": { - "version": "3.20.3", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.20.3.tgz", - "integrity": "sha512-FfHJ/QCpo4K2gquBX7dIAcmShSBG4dMtYJ3ghSiR4w7YqlUujuamrM57C+mKLNWS3mvZzmm2B2Qx8Q6Gfw+lDQ==", - "dev": true, - "optional": true, - "dependencies": { - "strnum": "^1.0.4" - }, - "bin": { - "xml2js": "cli.js" - }, - "funding": { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" - } - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, - "optional": true, - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "dependencies": { - "flat-cache": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/file-type": { - "version": "12.4.2", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-12.4.2.tgz", - "integrity": "sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, - "node_modules/filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/filename-reserved-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", - "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/filenamify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", - "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", - "dev": true, - "optional": true, - "dependencies": { - "filename-reserved-regex": "^2.0.0", - "strip-outer": "^1.0.0", - "trim-repeated": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/find-versions": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", - "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", - "dev": true, - "optional": true, - "dependencies": { - "semver-regex": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", - "dev": true, - "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/fined/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/first-chunk-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz", - "integrity": "sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "dependencies": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/flatpickr": { - "version": "4.6.9", - "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.9.tgz", - "integrity": "sha512-F0azNNi8foVWKSF+8X+ZJzz8r9sE1G4hl06RyceIaLvyltKvDl6vqk9Lm/6AUUCi5HWaIjiUbk7UpeE/fOXOpw==" - }, - "node_modules/flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "node_modules/flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "node_modules/follow-redirects": { - "version": "1.14.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", - "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/font-awesome": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", - "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=", - "engines": { - "node": ">=0.10.3" - } - }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "dependencies": { - "for-in": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "dependencies": { - "map-cache": "^0.2.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "optional": true, - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "node_modules/fs": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.2.tgz", - "integrity": "sha1-4fJE7zkzwbKmS9R5kTYGDQ9ZFPg=", - "dev": true - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "optional": true - }, - "node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs-mkdirp-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", - "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "through2": "^2.0.3" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/fs-readfile-promise": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fs-readfile-promise/-/fs-readfile-promise-3.0.1.tgz", - "integrity": "sha512-LsSxMeaJdYH27XrW7Dmq0Gx63mioULCRel63B5VeELYLavi1wF5s0XfsIdKDFdCL9hsfQ2qBvXJszQtQJ9h17A==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proxy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", - "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", - "dev": true, - "optional": true, - "dependencies": { - "npm-conf": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "optional": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/gifsicle": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/gifsicle/-/gifsicle-5.2.1.tgz", - "integrity": "sha512-9ewIQQCAnSmkU2DhuWafd1DdsgzAkKqIWnY+023xBLSiK9Az2TDUozWQW+SyRQgFMclbe6RQldUk/49TRO3Aqw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "dependencies": { - "bin-build": "^3.0.0", - "bin-wrapper": "^4.0.0", - "execa": "^5.0.0" - }, - "bin": { - "gifsicle": "cli.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/imagemin/gisicle-bin?sponsor=1" - } - }, - "node_modules/gifsicle/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "optional": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/gifsicle/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "optional": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/gifsicle/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gifsicle/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gifsicle/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "optional": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/gifsicle/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/gifsicle/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "optional": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/gifsicle/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/gifsicle/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "optional": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "dev": true, - "dependencies": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-base/node_modules/glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "dependencies": { - "is-glob": "^2.0.0" - } - }, - "node_modules/glob-base/node_modules/is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-base/node_modules/is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "dependencies": { - "is-extglob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-stream": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", - "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", - "dev": true, - "dependencies": { - "extend": "^3.0.0", - "glob": "^7.1.1", - "glob-parent": "^3.1.0", - "is-negated-glob": "^1.0.0", - "ordered-read-streams": "^1.0.0", - "pumpify": "^1.3.5", - "readable-stream": "^2.1.5", - "remove-trailing-separator": "^1.0.1", - "to-absolute-glob": "^2.0.0", - "unique-stream": "^2.0.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/glob-watcher": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", - "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", - "dev": true, - "dependencies": { - "anymatch": "^2.0.0", - "async-done": "^1.2.0", - "chokidar": "^2.0.0", - "is-negated-glob": "^1.0.0", - "just-debounce": "^1.0.0", - "normalize-path": "^3.0.0", - "object.defaults": "^1.1.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "dependencies": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/globby": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", - "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", - "dev": true, - "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/globby/node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/globby/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/glogg": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", - "dev": true, - "dependencies": { - "sparkles": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/good-listener": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", - "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", - "dependencies": { - "delegate": "^3.1.2" - } - }, - "node_modules/got": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", - "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", - "dev": true, - "optional": true, - "dependencies": { - "decompress-response": "^3.2.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-plain-obj": "^1.1.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "p-cancelable": "^0.3.0", - "p-timeout": "^1.1.1", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "url-parse-lax": "^1.0.0", - "url-to-options": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/got/node_modules/get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" - }, - "node_modules/growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true - }, - "node_modules/gulp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", - "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", - "dev": true, - "dependencies": { - "glob-watcher": "^5.0.3", - "gulp-cli": "^2.2.0", - "undertaker": "^1.2.1", - "vinyl-fs": "^3.0.0" - }, - "bin": { - "gulp": "bin/gulp.js" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/gulp-angular-embed-templates": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/gulp-angular-embed-templates/-/gulp-angular-embed-templates-2.3.0.tgz", - "integrity": "sha1-wBDv3VlN7pRRMoNFN9eSOt6EDXk=", - "dev": true, - "dependencies": { - "gulp-util": "^3.0.6", - "htmlparser2": "~3.9.1", - "minimize": "^2.0.0", - "object-assign": "4.1.0", - "through2": "^2.0.1" - } - }, - "node_modules/gulp-babel": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/gulp-babel/-/gulp-babel-8.0.0.tgz", - "integrity": "sha512-oomaIqDXxFkg7lbpBou/gnUkX51/Y/M2ZfSjL2hdqXTAlSWZcgZtd2o0cOH0r/eE8LWD0+Q/PsLsr2DKOoqToQ==", - "dev": true, - "dependencies": { - "plugin-error": "^1.0.1", - "replace-ext": "^1.0.0", - "through2": "^2.0.0", - "vinyl-sourcemaps-apply": "^0.2.0" - }, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/gulp-clean-css": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.2.0.tgz", - "integrity": "sha512-r4zQsSOAK2UYUL/ipkAVCTRg/2CLZ2A+oPVORopBximRksJ6qy3EX1KGrIWT4ZrHxz3Hlobb1yyJtqiut7DNjA==", - "dev": true, - "dependencies": { - "clean-css": "4.2.1", - "plugin-error": "1.0.1", - "through2": "3.0.1", - "vinyl-sourcemaps-apply": "0.2.1" - } - }, - "node_modules/gulp-clean-css/node_modules/through2": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", - "dev": true, - "dependencies": { - "readable-stream": "2 || 3" - } - }, - "node_modules/gulp-cli": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", - "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", - "dev": true, - "dependencies": { - "ansi-colors": "^1.0.1", - "archy": "^1.0.0", - "array-sort": "^1.0.0", - "color-support": "^1.1.3", - "concat-stream": "^1.6.0", - "copy-props": "^2.0.1", - "fancy-log": "^1.3.2", - "gulplog": "^1.0.0", - "interpret": "^1.4.0", - "isobject": "^3.0.1", - "liftoff": "^3.1.0", - "matchdep": "^2.0.0", - "mute-stdout": "^1.0.0", - "pretty-hrtime": "^1.0.0", - "replace-homedir": "^1.0.0", - "semver-greatest-satisfied-range": "^1.1.0", - "v8flags": "^3.2.0", - "yargs": "^7.1.0" - }, - "bin": { - "gulp": "bin/gulp.js" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/gulp-concat": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", - "integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=", - "dev": true, - "dependencies": { - "concat-with-sourcemaps": "^1.0.0", - "through2": "^2.0.0", - "vinyl": "^2.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/gulp-eslint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-6.0.0.tgz", - "integrity": "sha512-dCVPSh1sA+UVhn7JSQt7KEb4An2sQNbOdB3PA8UCfxsoPlAKjJHxYHGXdXC7eb+V1FAnilSFFqslPrq037l1ig==", - "dev": true, - "dependencies": { - "eslint": "^6.0.0", - "fancy-log": "^1.3.2", - "plugin-error": "^1.0.1" - } - }, - "node_modules/gulp-imagemin": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/gulp-imagemin/-/gulp-imagemin-7.1.0.tgz", - "integrity": "sha512-6xBTNybmPY2YrvrhhlS8Mxi0zn0ypusLon63p9XXxDtIf7U7c6KcViz94K7Skosucr3378A6IY2kJSjJyuwylQ==", - "dev": true, - "dependencies": { - "chalk": "^3.0.0", - "fancy-log": "^1.3.2", - "imagemin": "^7.0.0", - "plugin-error": "^1.0.1", - "plur": "^3.0.1", - "pretty-bytes": "^5.3.0", - "through2-concurrent": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - }, - "optionalDependencies": { - "imagemin-gifsicle": "^7.0.0", - "imagemin-mozjpeg": "^8.0.0", - "imagemin-optipng": "^7.0.0", - "imagemin-svgo": "^7.0.0" - }, - "peerDependencies": { - "gulp": ">=4" - }, - "peerDependenciesMeta": { - "gulp": { - "optional": true - } - } - }, - "node_modules/gulp-imagemin/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/gulp-imagemin/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/gulp-imagemin/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/gulp-imagemin/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/gulp-imagemin/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/gulp-less": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/gulp-less/-/gulp-less-4.0.1.tgz", - "integrity": "sha512-hmM2k0FfQp7Ptm3ZaqO2CkMX3hqpiIOn4OHtuSsCeFym63F7oWlEua5v6u1cIjVUKYsVIs9zPg9vbqTEb/udpA==", - "dev": true, - "dependencies": { - "accord": "^0.29.0", - "less": "2.6.x || ^3.7.1", - "object-assign": "^4.0.1", - "plugin-error": "^0.1.2", - "replace-ext": "^1.0.0", - "through2": "^2.0.0", - "vinyl-sourcemaps-apply": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-less/node_modules/arr-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", - "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", - "dev": true, - "dependencies": { - "arr-flatten": "^1.0.1", - "array-slice": "^0.2.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-less/node_modules/arr-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", - "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-less/node_modules/array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-less/node_modules/extend-shallow": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", - "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", - "dev": true, - "dependencies": { - "kind-of": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-less/node_modules/kind-of": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-less/node_modules/plugin-error": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", - "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", - "dev": true, - "dependencies": { - "ansi-cyan": "^0.1.1", - "ansi-red": "^0.1.1", - "arr-diff": "^1.0.1", - "arr-union": "^2.0.1", - "extend-shallow": "^1.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-minify": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/gulp-minify/-/gulp-minify-3.1.0.tgz", - "integrity": "sha512-ixF41aYg+NQikI8hpoHdEclYcQkbGdXQu1CBdHaU7Epg8H6e8d2jWXw1+rBPgYwl/XpKgjHj7NI6gkhoSNSSAg==", - "dev": true, - "dependencies": { - "ansi-colors": "^1.0.1", - "minimatch": "^3.0.2", - "plugin-error": "^0.1.2", - "terser": "^3.7.6", - "through2": "^2.0.3", - "vinyl": "^2.1.0" - } - }, - "node_modules/gulp-minify/node_modules/arr-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", - "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", - "dev": true, - "dependencies": { - "arr-flatten": "^1.0.1", - "array-slice": "^0.2.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-minify/node_modules/arr-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", - "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-minify/node_modules/array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-minify/node_modules/extend-shallow": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", - "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", - "dev": true, - "dependencies": { - "kind-of": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-minify/node_modules/kind-of": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-minify/node_modules/plugin-error": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", - "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", - "dev": true, - "dependencies": { - "ansi-cyan": "^0.1.1", - "ansi-red": "^0.1.1", - "arr-diff": "^1.0.1", - "arr-union": "^2.0.1", - "extend-shallow": "^1.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-notify": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/gulp-notify/-/gulp-notify-3.2.0.tgz", - "integrity": "sha512-qEocs1UVoDKKUjfsxJNMNwkRla0PbsyJwsqNNXpzYWsLQ29LhxRMY3wnTGZcc4hMHtalnvah/Dwlwb4NijH/0A==", - "dev": true, - "dependencies": { - "ansi-colors": "^1.0.1", - "fancy-log": "^1.3.2", - "lodash.template": "^4.4.0", - "node-notifier": "^5.2.1", - "node.extend": "^2.0.0", - "plugin-error": "^0.1.2", - "through2": "^2.0.3" - }, - "engines": { - "node": ">=0.8.0", - "npm": ">=1.2.10" - } - }, - "node_modules/gulp-notify/node_modules/arr-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", - "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", - "dev": true, - "dependencies": { - "arr-flatten": "^1.0.1", - "array-slice": "^0.2.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-notify/node_modules/arr-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", - "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-notify/node_modules/array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-notify/node_modules/extend-shallow": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", - "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", - "dev": true, - "dependencies": { - "kind-of": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-notify/node_modules/kind-of": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-notify/node_modules/plugin-error": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", - "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", - "dev": true, - "dependencies": { - "ansi-cyan": "^0.1.1", - "ansi-red": "^0.1.1", - "arr-diff": "^1.0.1", - "arr-union": "^2.0.1", - "extend-shallow": "^1.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-postcss": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/gulp-postcss/-/gulp-postcss-8.0.0.tgz", - "integrity": "sha512-Wtl6vH7a+8IS/fU5W9IbOpcaLqKxd5L1DUOzaPmlnCbX1CrG0aWdwVnC3Spn8th0m8D59YbysV5zPUe1n/GJYg==", - "dev": true, - "dependencies": { - "fancy-log": "^1.3.2", - "plugin-error": "^1.0.1", - "postcss": "^7.0.2", - "postcss-load-config": "^2.0.0", - "vinyl-sourcemaps-apply": "^0.2.1" - } - }, - "node_modules/gulp-rename": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.4.0.tgz", - "integrity": "sha512-swzbIGb/arEoFK89tPY58vg3Ok1bw+d35PfUNwWqdo7KM4jkmuGA78JiDNqR+JeZFaeeHnRg9N7aihX3YPmsyg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/gulp-sort": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/gulp-sort/-/gulp-sort-2.0.0.tgz", - "integrity": "sha1-xnYqLx8N4KP8WVohWZ0/rI26Gso=", - "dev": true, - "dependencies": { - "through2": "^2.0.1" - } - }, - "node_modules/gulp-sourcemaps": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz", - "integrity": "sha512-SYLBRzPTew8T5Suh2U8jCSDKY+4NARua4aqjj8HOysBh2tSgT9u4jc1FYirAdPx1akUxxDeK++fqw6Jg0LkQRg==", - "dev": true, - "dependencies": { - "@gulp-sourcemaps/identity-map": "1.X", - "@gulp-sourcemaps/map-sources": "1.X", - "acorn": "5.X", - "convert-source-map": "1.X", - "css": "2.X", - "debug-fabulous": "1.X", - "detect-newline": "2.X", - "graceful-fs": "4.X", - "source-map": "~0.6.0", - "strip-bom-string": "1.X", - "through2": "2.X" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/gulp-sourcemaps/node_modules/acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/gulp-sourcemaps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-util": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", - "deprecated": "gulp-util is deprecated - replace it, following the guidelines at https://medium.com/gulpjs/gulp-util-ca3b1f9f9ac5", - "dev": true, - "dependencies": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", - "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/gulp-util/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-util/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-util/node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/gulp-util/node_modules/clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "node_modules/gulp-util/node_modules/lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", - "dev": true, - "dependencies": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "node_modules/gulp-util/node_modules/lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", - "dev": true, - "dependencies": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" - } - }, - "node_modules/gulp-util/node_modules/object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-util/node_modules/replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gulp-util/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-util/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/gulp-util/node_modules/vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", - "dev": true, - "dependencies": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - }, - "engines": { - "node": ">= 0.9" - } - }, - "node_modules/gulp-watch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/gulp-watch/-/gulp-watch-5.0.1.tgz", - "integrity": "sha512-HnTSBdzAOFIT4wmXYPDUn783TaYAq9bpaN05vuZNP5eni3z3aRx0NAKbjhhMYtcq76x4R1wf4oORDGdlrEjuog==", - "dev": true, - "dependencies": { - "ansi-colors": "1.1.0", - "anymatch": "^1.3.0", - "chokidar": "^2.0.0", - "fancy-log": "1.3.2", - "glob-parent": "^3.0.1", - "object-assign": "^4.1.0", - "path-is-absolute": "^1.0.1", - "plugin-error": "1.0.1", - "readable-stream": "^2.2.2", - "slash": "^1.0.0", - "vinyl": "^2.1.0", - "vinyl-file": "^2.0.0" - } - }, - "node_modules/gulp-watch/node_modules/anymatch": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", - "dev": true, - "dependencies": { - "micromatch": "^2.1.5", - "normalize-path": "^2.0.0" - } - }, - "node_modules/gulp-watch/node_modules/arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "dependencies": { - "arr-flatten": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-watch/node_modules/array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-watch/node_modules/braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "dependencies": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-watch/node_modules/expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "dependencies": { - "is-posix-bracket": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-watch/node_modules/extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "dependencies": { - "is-extglob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-watch/node_modules/fancy-log": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", - "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", - "dev": true, - "dependencies": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "time-stamp": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/gulp-watch/node_modules/is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-watch/node_modules/is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "dependencies": { - "is-extglob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-watch/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-watch/node_modules/micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "dependencies": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-watch/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-wrap": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/gulp-wrap/-/gulp-wrap-0.15.0.tgz", - "integrity": "sha512-f17zkGObA+hE/FThlg55gfA0nsXbdmHK1WqzjjB2Ytq1TuhLR7JiCBJ3K4AlMzCyoFaCjfowos+VkToUNE0WTQ==", - "dev": true, - "dependencies": { - "consolidate": "^0.15.1", - "es6-promise": "^4.2.6", - "fs-readfile-promise": "^3.0.1", - "js-yaml": "^3.13.0", - "lodash": "^4.17.11", - "node.extend": "2.0.2", - "plugin-error": "^1.0.1", - "through2": "^3.0.1", - "tryit": "^1.0.1", - "vinyl-bufferstream": "^1.0.1" - }, - "engines": { - "node": ">=6.14", - "npm": ">=1.4.3" - } - }, - "node_modules/gulp-wrap-js": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/gulp-wrap-js/-/gulp-wrap-js-0.4.1.tgz", - "integrity": "sha1-3uYqpISqupVHqT0f9c0MPQvtwDE=", - "dev": true, - "dependencies": { - "escodegen": "^1.6.1", - "esprima": "^2.3.0", - "estemplate": "*", - "gulp-util": "~3.0.5", - "through2": "*", - "vinyl-sourcemaps-apply": "^0.1.4" - }, - "engines": { - "node": ">=0.8.0", - "npm": ">=1.2.10" - } - }, - "node_modules/gulp-wrap-js/node_modules/source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", - "dev": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/gulp-wrap-js/node_modules/vinyl-sourcemaps-apply": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.1.4.tgz", - "integrity": "sha1-xfy9Q+LyOEI8LcmL3db3m3K8NFs=", - "dev": true, - "dependencies": { - "source-map": "^0.1.39" - } - }, - "node_modules/gulp-wrap/node_modules/through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - }, - "node_modules/gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", - "dev": true, - "dependencies": { - "glogg": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-binary2": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", - "dev": true, - "dependencies": { - "isarray": "2.0.1" - } - }, - "node_modules/has-binary2/node_modules/isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", - "dev": true - }, - "node_modules/has-cors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", - "dev": true - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", - "dev": true, - "dependencies": { - "sparkles": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/has-symbol-support-x": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", - "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", - "dev": true, - "optional": true, - "engines": { - "node": "*" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-to-string-tag-x": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", - "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", - "dev": true, - "optional": true, - "dependencies": { - "has-symbol-support-x": "^1.4.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hex-color-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", - "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", - "dev": true - }, - "node_modules/homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "dependencies": { - "parse-passwd": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" - }, - "node_modules/hsl-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", - "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", - "dev": true - }, - "node_modules/hsla-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", - "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", - "dev": true - }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^1.0.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/htmlparser2": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", - "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", - "dev": true, - "dependencies": { - "domelementtype": "^1.3.0", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^2.0.2" - } - }, - "node_modules/http-cache-semantics": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", - "dev": true, - "optional": true - }, - "node_modules/http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "dev": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/http-errors/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", - "dev": true, - "optional": true, - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/imagemin": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/imagemin/-/imagemin-7.0.1.tgz", - "integrity": "sha512-33AmZ+xjZhg2JMCe+vDf6a9mzWukE7l+wAtesjE7KyteqqKjzxv7aVQeWnul1Ve26mWvEQqyPwl0OctNBfSR9w==", - "dev": true, - "dependencies": { - "file-type": "^12.0.0", - "globby": "^10.0.0", - "graceful-fs": "^4.2.2", - "junk": "^3.1.0", - "make-dir": "^3.0.0", - "p-pipe": "^3.0.0", - "replace-ext": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/imagemin-gifsicle": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/imagemin-gifsicle/-/imagemin-gifsicle-7.0.0.tgz", - "integrity": "sha512-LaP38xhxAwS3W8PFh4y5iQ6feoTSF+dTAXFRUEYQWYst6Xd+9L/iPk34QGgK/VO/objmIlmq9TStGfVY2IcHIA==", - "dev": true, - "optional": true, - "dependencies": { - "execa": "^1.0.0", - "gifsicle": "^5.0.0", - "is-gif": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/imagemin/imagemin-gifsicle?sponsor=1" - } - }, - "node_modules/imagemin-mozjpeg": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/imagemin-mozjpeg/-/imagemin-mozjpeg-8.0.0.tgz", - "integrity": "sha512-+EciPiIjCb8JWjQNr1q8sYWYf7GDCNDxPYnkD11TNIjjWNzaV+oTg4DpOPQjl5ZX/KRCPMEgS79zLYAQzLitIA==", - "dev": true, - "optional": true, - "dependencies": { - "execa": "^1.0.0", - "is-jpg": "^2.0.0", - "mozjpeg": "^6.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/imagemin-optipng": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/imagemin-optipng/-/imagemin-optipng-7.1.0.tgz", - "integrity": "sha512-JNORTZ6j6untH7e5gF4aWdhDCxe3ODsSLKs/f7Grewy3ebZpl1ZsU+VUTPY4rzeHgaFA8GSWOoA8V2M3OixWZQ==", - "dev": true, - "optional": true, - "dependencies": { - "exec-buffer": "^3.0.0", - "is-png": "^2.0.0", - "optipng-bin": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/imagemin-svgo": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/imagemin-svgo/-/imagemin-svgo-7.1.0.tgz", - "integrity": "sha512-0JlIZNWP0Luasn1HT82uB9nU9aa+vUj6kpT+MjPW11LbprXC+iC4HDwn1r4Q2/91qj4iy9tRZNsFySMlEpLdpg==", - "dev": true, - "optional": true, - "dependencies": { - "is-svg": "^4.2.1", - "svgo": "^1.3.2" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sindresorhus/imagemin-svgo?sponsor=1" - } - }, - "node_modules/import-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", - "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", - "dev": true, - "dependencies": { - "import-from": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-from": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", - "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", - "dev": true, - "dependencies": { - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-lazy": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-3.1.0.tgz", - "integrity": "sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "optional": true, - "dependencies": { - "repeating": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true - }, - "node_modules/indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", - "dev": true - }, - "node_modules/indx": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/indx/-/indx-0.2.3.tgz", - "integrity": "sha1-Fdz1bunPZcAjTFE8J/vVgOcPvFA=", - "dev": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/inquirer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/into-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", - "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", - "dev": true, - "optional": true, - "dependencies": { - "from2": "^2.1.1", - "p-is-promise": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/irregular-plurals": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-2.0.0.tgz", - "integrity": "sha512-Y75zBYLkh0lJ9qxeHlMjQ7bSbyiSqNW/UOPWDmzC7cXskL1hekSITh1Oc6JV0XCWWZ9DE8VYSB71xocLk3gmGw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", - "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", - "dev": true, - "dependencies": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-absolute-url": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", - "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "dependencies": { - "binary-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-color-stop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", - "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", - "dev": true, - "dependencies": { - "css-color-names": "^0.0.4", - "hex-color-regex": "^1.1.0", - "hsl-regex": "^1.0.0", - "hsla-regex": "^1.0.0", - "rgb-regex": "^1.0.1", - "rgba-regex": "^1.0.0" - } - }, - "node_modules/is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true, - "dependencies": { - "is-primitive": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finite": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", - "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-gif": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-gif/-/is-gif-3.0.0.tgz", - "integrity": "sha512-IqJ/jlbw5WJSNfwQ/lHEDXF8rxhRgF6ythk2oiEvhpG29F704eX9NO6TvPfMiq9DrbwgcEDnETYNcZDPewQoVw==", - "dev": true, - "optional": true, - "dependencies": { - "file-type": "^10.4.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-gif/node_modules/file-type": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-10.11.0.tgz", - "integrity": "sha512-uzk64HRpUZyTGZtVuvrjP0FYxzQrBf4rojot6J65YMEbwBLB0CWm0CLojVpwpmFmxcE/lkvYICgfcGozbBq6rw==", - "dev": true, - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-jpg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-jpg/-/is-jpg-2.0.0.tgz", - "integrity": "sha1-LhmX+m6RZuqsAkLarkQ0A+TvHZc=", - "dev": true, - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-natural-number": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", - "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=", - "dev": true, - "optional": true - }, - "node_modules/is-negated-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", - "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true, - "optional": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-png": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-png/-/is-png-2.0.0.tgz", - "integrity": "sha512-4KPGizaVGj2LK7xwJIz8o5B2ubu1D/vcQsgOGFEDlpcvgZHto4gBnyd0ig7Ws+67ixmwKoNmu0hYnpo6AaKb5g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", - "dev": true, - "dependencies": { - "is-unc-path": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, - "node_modules/is-retry-allowed": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-svg": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-4.3.1.tgz", - "integrity": "sha512-h2CGs+yPUyvkgTJQS9cJzo9lYK06WgRiXUqBBHtglSzVKAuH4/oWsqk7LGfbSa1hGk9QcZ0SyQtVggvBA8LZXA==", - "dev": true, - "optional": true, - "dependencies": { - "fast-xml-parser": "^3.19.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "node_modules/is-unc-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", - "dev": true, - "dependencies": { - "unc-path-regex": "^0.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "node_modules/is-valid-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", - "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-weakref": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "node_modules/isbinaryfile": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", - "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", - "dev": true, - "dependencies": { - "buffer-alloc": "^1.2.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "node_modules/isurl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", - "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", - "dev": true, - "optional": true, - "dependencies": { - "has-to-string-tag-x": "^1.2.0", - "is-object": "^1.0.1" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/jasmine-core": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.5.0.tgz", - "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==", - "dev": true - }, - "node_modules/jquery": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", - "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" - }, - "node_modules/jquery-ui-dist": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/jquery-ui-dist/-/jquery-ui-dist-1.12.1.tgz", - "integrity": "sha1-XAgV08xvkP9fqvWyaKbiO0ypBPo=" - }, - "node_modules/jquery-ui-touch-punch": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/jquery-ui-touch-punch/-/jquery-ui-touch-punch-0.2.3.tgz", - "integrity": "sha1-7tgiQnM7okP0az6HwYQbMIGR2mg=" - }, - "node_modules/js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/js-yaml/node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "node_modules/jsdom": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz", - "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==", - "dev": true, - "dependencies": { - "abab": "^2.0.3", - "acorn": "^7.1.1", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.2.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.0", - "domexception": "^2.0.1", - "escodegen": "^1.14.1", - "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", - "nwsapi": "^2.2.0", - "parse5": "5.1.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.8", - "saxes": "^5.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^3.0.1", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0", - "ws": "^7.2.3", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/ws": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", - "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", - "dev": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", - "dev": true, - "optional": true - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "node_modules/json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "node_modules/junk": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz", - "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/just-debounce": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", - "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==", - "dev": true - }, - "node_modules/karma": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/karma/-/karma-4.4.1.tgz", - "integrity": "sha512-L5SIaXEYqzrh6b1wqYC42tNsFMx2PWuxky84pK9coK09MvmL7mxii3G3bZBh/0rvD27lqDd0le9jyhzvwif73A==", - "dev": true, - "dependencies": { - "bluebird": "^3.3.0", - "body-parser": "^1.16.1", - "braces": "^3.0.2", - "chokidar": "^3.0.0", - "colors": "^1.1.0", - "connect": "^3.6.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.0", - "flatted": "^2.0.0", - "glob": "^7.1.1", - "graceful-fs": "^4.1.2", - "http-proxy": "^1.13.0", - "isbinaryfile": "^3.0.0", - "lodash": "^4.17.14", - "log4js": "^4.0.0", - "mime": "^2.3.1", - "minimatch": "^3.0.2", - "optimist": "^0.6.1", - "qjobs": "^1.1.4", - "range-parser": "^1.2.0", - "rimraf": "^2.6.0", - "safe-buffer": "^5.0.1", - "socket.io": "2.1.1", - "source-map": "^0.6.1", - "tmp": "0.0.33", - "useragent": "2.3.0" - }, - "bin": { - "karma": "bin/karma" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/karma-jasmine": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-2.0.1.tgz", - "integrity": "sha512-iuC0hmr9b+SNn1DaUD2QEYtUxkS1J+bSJSn7ejdEexs7P8EYvA1CWkEdrDQ+8jVH3AgWlCNwjYsT1chjcNW9lA==", - "dev": true, - "dependencies": { - "jasmine-core": "^3.3" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "karma": "*" - } - }, - "node_modules/karma-jsdom-launcher": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/karma-jsdom-launcher/-/karma-jsdom-launcher-8.0.2.tgz", - "integrity": "sha512-jxO+Nf9U/XNSnHXrNpxBbbMyeYuvJH1V++bRdZv20vJ9pvaLuQ6LFNIgn4hA1WAVmzMsvW9j0P2Q2hTLMWcSvw==", - "dev": true, - "peerDependencies": { - "jsdom": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", - "karma": "^1.4.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" - } - }, - "node_modules/karma-junit-reporter": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/karma-junit-reporter/-/karma-junit-reporter-2.0.1.tgz", - "integrity": "sha512-VtcGfE0JE4OE1wn0LK8xxDKaTP7slN8DO3I+4xg6gAi1IoAHAXOJ1V9G/y45Xg6sxdxPOR3THCFtDlAfBo9Afw==", - "dev": true, - "dependencies": { - "path-is-absolute": "^1.0.0", - "xmlbuilder": "12.0.0" - }, - "engines": { - "node": ">= 8" - }, - "peerDependencies": { - "karma": ">=0.9" - } - }, - "node_modules/karma-spec-reporter": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/karma-spec-reporter/-/karma-spec-reporter-0.0.32.tgz", - "integrity": "sha1-LpxyB+pyZ3EmAln4K+y1QyCeRAo=", - "dev": true, - "dependencies": { - "colors": "^1.1.2" - }, - "peerDependencies": { - "karma": ">=0.9" - } - }, - "node_modules/karma/node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/karma/node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/karma/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/karma/node_modules/chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/karma/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/karma/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/karma/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/karma/node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/karma/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/karma/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/karma/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/karma/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/keyv": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", - "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", - "dev": true, - "optional": true, - "dependencies": { - "json-buffer": "3.0.0" - } - }, - "node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kuler": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", - "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", - "dev": true, - "dependencies": { - "colornames": "^1.1.1" - } - }, - "node_modules/last-run": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", - "dev": true, - "dependencies": { - "default-resolution": "^2.0.0", - "es6-weak-map": "^2.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lazyload-js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lazyload-js/-/lazyload-js-1.0.0.tgz", - "integrity": "sha1-jBA5sbaRec1J/cMkICOvSM4IOSU=" - }, - "node_modules/lazystream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", - "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, - "dependencies": { - "invert-kv": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lead": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", - "dev": true, - "dependencies": { - "flush-write-stream": "^1.0.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/less": { - "version": "3.10.3", - "resolved": "https://registry.npmjs.org/less/-/less-3.10.3.tgz", - "integrity": "sha512-vz32vqfgmoxF1h3K4J+yKCtajH0PWmjkIFgbs5d78E/c/e+UQTnI+lWK+1eQRE95PXM2mC3rJlLSSP9VQHnaow==", - "dev": true, - "dependencies": { - "clone": "^2.1.2" - }, - "bin": { - "lessc": "bin/lessc" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "mime": "^1.4.1", - "mkdirp": "^0.5.0", - "promise": "^7.1.1", - "request": "^2.83.0", - "source-map": "~0.6.0" - } - }, - "node_modules/less/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "optional": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/less/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/liftoff": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", - "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", - "dev": true, - "dependencies": { - "extend": "^3.0.0", - "findup-sync": "^3.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/liftoff/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/load-json-file/node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/load-json-file/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "node_modules/lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true - }, - "node_modules/lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", - "dev": true - }, - "node_modules/lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" - }, - "node_modules/lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true - }, - "node_modules/lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", - "dev": true - }, - "node_modules/lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true - }, - "node_modules/lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - }, - "node_modules/lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", - "dev": true - }, - "node_modules/lodash.clone": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", - "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=", - "dev": true - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", - "dev": true - }, - "node_modules/lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", - "dev": true, - "dependencies": { - "lodash._root": "^3.0.0" - } - }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", - "dev": true - }, - "node_modules/lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "node_modules/lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true - }, - "node_modules/lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "dependencies": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.partialright": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.partialright/-/lodash.partialright-4.2.1.tgz", - "integrity": "sha1-ATDYDoM2MmTUAHTzKbij56ihzEs=", - "dev": true - }, - "node_modules/lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=", - "dev": true - }, - "node_modules/lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" - }, - "node_modules/lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "dev": true, - "dependencies": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "node_modules/lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", - "dev": true, - "dependencies": { - "lodash._reinterpolate": "^3.0.0" - } - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" - }, - "node_modules/log4js": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.5.1.tgz", - "integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==", - "dev": true, - "dependencies": { - "date-format": "^2.0.0", - "debug": "^4.1.1", - "flatted": "^2.0.0", - "rfdc": "^1.1.4", - "streamroller": "^1.0.6" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/logalot": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/logalot/-/logalot-2.1.0.tgz", - "integrity": "sha1-X46MkNME7fElMJUaVVSruMXj9VI=", - "dev": true, - "optional": true, - "dependencies": { - "figures": "^1.3.5", - "squeak": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/logalot/node_modules/figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "optional": true, - "dependencies": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", - "dev": true, - "optional": true, - "dependencies": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lpad-align": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/lpad-align/-/lpad-align-1.1.2.tgz", - "integrity": "sha1-IfYArBwwlcPG5JfuZyce4ISB/p4=", - "dev": true, - "optional": true, - "dependencies": { - "get-stdin": "^4.0.1", - "indent-string": "^2.1.0", - "longest": "^1.0.0", - "meow": "^3.3.0" - }, - "bin": { - "lpad-align": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", - "dev": true, - "dependencies": { - "es5-ext": "~0.10.2" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/make-iterator/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "dependencies": { - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/marked": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", - "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==", - "dev": true, - "bin": { - "marked": "bin/marked" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", - "dev": true, - "dependencies": { - "findup-sync": "^2.0.0", - "micromatch": "^3.0.4", - "resolve": "^1.4.0", - "stack-trace": "0.0.10" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/matchdep/node_modules/findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", - "dev": true, - "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/matchdep/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/math-random": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", - "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", - "dev": true - }, - "node_modules/mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", - "dev": true - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memoizee": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", - "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - } - }, - "node_modules/meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", - "dev": true, - "optional": true, - "dependencies": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/micromatch/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mime": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", - "dependencies": { - "mime-db": "1.50.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "node_modules/minimize": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/minimize/-/minimize-2.2.0.tgz", - "integrity": "sha512-IxR2XMbw9pXCxApkdD9BTcH2U4XlXhbeySUrv71rmMS9XDA8BVXEsIuFu24LtwCfBgfbL7Fuh8/ZzkO5DaTLlQ==", - "dev": true, - "dependencies": { - "argh": "^0.1.4", - "async": "^2.1.5", - "cli-color": "^1.2.0", - "diagnostics": "^1.1.0", - "emits": "^3.0.0", - "htmlparser2": "^3.9.2", - "uuid": "^3.0.0" - }, - "bin": { - "minimize": "bin/minimize" - } - }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/moment": { - "version": "2.22.2", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", - "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=", - "engines": { - "node": "*" - } - }, - "node_modules/mozjpeg": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/mozjpeg/-/mozjpeg-6.0.1.tgz", - "integrity": "sha512-9Z59pJMi8ni+IUvSH5xQwK5tNLw7p3dwDNCZ3o1xE+of3G5Hc/yOz6Ue/YuLiBXU3ZB5oaHPURyPdqfBX/QYJA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "dependencies": { - "bin-build": "^3.0.0", - "bin-wrapper": "^4.0.0", - "logalot": "^2.1.0" - }, - "bin": { - "mozjpeg": "cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", - "dev": true, - "dependencies": { - "duplexer2": "0.0.2" - } - }, - "node_modules/mute-stdout": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", - "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", - "dev": true, - "optional": true - }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "dev": true - }, - "node_modules/ng-file-upload": { - "version": "12.2.13", - "resolved": "https://registry.npmjs.org/ng-file-upload/-/ng-file-upload-12.2.13.tgz", - "integrity": "sha1-AYAPOHLlJvlTEPhHfpnk8S0NjRQ=" - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/node-notifier": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.5.tgz", - "integrity": "sha512-tVbHs7DyTLtzOiN78izLA85zRqB9NvEXkAf014Vx3jtSvn/xBl6bR8ZYifj+dFcFrKI21huSQgJZ6ZtL3B4HfQ==", - "dev": true, - "dependencies": { - "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", - "shellwords": "^0.1.1", - "which": "^1.3.0" - } - }, - "node_modules/node-releases": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", - "integrity": "sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==", - "dev": true - }, - "node_modules/node.extend": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-2.0.2.tgz", - "integrity": "sha512-pDT4Dchl94/+kkgdwyS2PauDFjZG0Hk0IcHIB+LkW27HLDtdoeMxHTxZh39DYbPP8UflWXWj9JcdDozF+YDOpQ==", - "dev": true, - "dependencies": { - "has": "^1.0.3", - "is": "^3.2.1" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/nouislider": { - "version": "15.4.0", - "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-15.4.0.tgz", - "integrity": "sha512-AV7UMhGhZ4Mj6ToMT812Ib8OJ4tAXR2/Um7C4l4ZvvsqujF0WpQTpqqHJ+9xt4174R7ueQOUrBR4yakJpAIPCA==" - }, - "node_modules/now-and-later": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", - "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", - "dev": true, - "dependencies": { - "once": "^1.3.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/npm": { - "version": "6.14.15", - "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.15.tgz", - "integrity": "sha512-dkcQc4n+DiJAMYG2haNAMyJbmuvevjXz+WC9dCUzodw8EovwTIc6CATSsTEplCY6c0jG4OshxFGFJsrnKJguWA==", - "bundleDependencies": [ - "abbrev", - "ansicolors", - "ansistyles", - "aproba", - "archy", - "bin-links", - "bluebird", - "byte-size", - "cacache", - "call-limit", - "chownr", - "ci-info", - "cli-columns", - "cli-table3", - "cmd-shim", - "columnify", - "config-chain", - "debuglog", - "detect-indent", - "detect-newline", - "dezalgo", - "editor", - "figgy-pudding", - "find-npm-prefix", - "fs-vacuum", - "fs-write-stream-atomic", - "gentle-fs", - "glob", - "graceful-fs", - "has-unicode", - "hosted-git-info", - "iferr", - "imurmurhash", - "infer-owner", - "inflight", - "inherits", - "ini", - "init-package-json", - "is-cidr", - "json-parse-better-errors", - "JSONStream", - "lazy-property", - "libcipm", - "libnpm", - "libnpmaccess", - "libnpmhook", - "libnpmorg", - "libnpmsearch", - "libnpmteam", - "libnpx", - "lock-verify", - "lockfile", - "lodash._baseindexof", - "lodash._baseuniq", - "lodash._bindcallback", - "lodash._cacheindexof", - "lodash._createcache", - "lodash._getnative", - "lodash.clonedeep", - "lodash.restparam", - "lodash.union", - "lodash.uniq", - "lodash.without", - "lru-cache", - "meant", - "mississippi", - "mkdirp", - "move-concurrently", - "node-gyp", - "nopt", - "normalize-package-data", - "npm-audit-report", - "npm-cache-filename", - "npm-install-checks", - "npm-lifecycle", - "npm-package-arg", - "npm-packlist", - "npm-pick-manifest", - "npm-profile", - "npm-registry-fetch", - "npm-user-validate", - "npmlog", - "once", - "opener", - "osenv", - "pacote", - "path-is-inside", - "promise-inflight", - "qrcode-terminal", - "query-string", - "qw", - "read-cmd-shim", - "read-installed", - "read-package-json", - "read-package-tree", - "read", - "readable-stream", - "readdir-scoped-modules", - "request", - "retry", - "rimraf", - "safe-buffer", - "semver", - "sha", - "slide", - "sorted-object", - "sorted-union-stream", - "ssri", - "stringify-package", - "tar", - "text-table", - "tiny-relative-date", - "uid-number", - "umask", - "unique-filename", - "unpipe", - "update-notifier", - "uuid", - "validate-npm-package-license", - "validate-npm-package-name", - "which", - "worker-farm", - "write-file-atomic" - ], - "dependencies": { - "abbrev": "~1.1.1", - "ansicolors": "~0.3.2", - "ansistyles": "~0.1.3", - "aproba": "^2.0.0", - "archy": "~1.0.0", - "bin-links": "^1.1.8", - "bluebird": "^3.5.5", - "byte-size": "^5.0.1", - "cacache": "^12.0.3", - "call-limit": "^1.1.1", - "chownr": "^1.1.4", - "ci-info": "^2.0.0", - "cli-columns": "^3.1.2", - "cli-table3": "^0.5.1", - "cmd-shim": "^3.0.3", - "columnify": "~1.5.4", - "config-chain": "^1.1.12", - "debuglog": "*", - "detect-indent": "~5.0.0", - "detect-newline": "^2.1.0", - "dezalgo": "~1.0.3", - "editor": "~1.0.0", - "figgy-pudding": "^3.5.1", - "find-npm-prefix": "^1.0.2", - "fs-vacuum": "~1.2.10", - "fs-write-stream-atomic": "~1.0.10", - "gentle-fs": "^2.3.1", - "glob": "^7.1.6", - "graceful-fs": "^4.2.4", - "has-unicode": "~2.0.1", - "hosted-git-info": "^2.8.9", - "iferr": "^1.0.2", - "imurmurhash": "*", - "infer-owner": "^1.0.4", - "inflight": "~1.0.6", - "inherits": "^2.0.4", - "ini": "^1.3.8", - "init-package-json": "^1.10.3", - "is-cidr": "^3.0.0", - "json-parse-better-errors": "^1.0.2", - "JSONStream": "^1.3.5", - "lazy-property": "~1.0.0", - "libcipm": "^4.0.8", - "libnpm": "^3.0.1", - "libnpmaccess": "^3.0.2", - "libnpmhook": "^5.0.3", - "libnpmorg": "^1.0.1", - "libnpmsearch": "^2.0.2", - "libnpmteam": "^1.0.2", - "libnpx": "^10.2.4", - "lock-verify": "^2.1.0", - "lockfile": "^1.0.4", - "lodash._baseindexof": "*", - "lodash._baseuniq": "~4.6.0", - "lodash._bindcallback": "*", - "lodash._cacheindexof": "*", - "lodash._createcache": "*", - "lodash._getnative": "*", - "lodash.clonedeep": "~4.5.0", - "lodash.restparam": "*", - "lodash.union": "~4.6.0", - "lodash.uniq": "~4.5.0", - "lodash.without": "~4.4.0", - "lru-cache": "^5.1.1", - "meant": "^1.0.2", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.5", - "move-concurrently": "^1.0.1", - "node-gyp": "^5.1.0", - "nopt": "^4.0.3", - "normalize-package-data": "^2.5.0", - "npm-audit-report": "^1.3.3", - "npm-cache-filename": "~1.0.2", - "npm-install-checks": "^3.0.2", - "npm-lifecycle": "^3.1.5", - "npm-package-arg": "^6.1.1", - "npm-packlist": "^1.4.8", - "npm-pick-manifest": "^3.0.2", - "npm-profile": "^4.0.4", - "npm-registry-fetch": "^4.0.7", - "npm-user-validate": "^1.0.1", - "npmlog": "~4.1.2", - "once": "~1.4.0", - "opener": "^1.5.2", - "osenv": "^0.1.5", - "pacote": "^9.5.12", - "path-is-inside": "~1.0.2", - "promise-inflight": "~1.0.1", - "qrcode-terminal": "^0.12.0", - "query-string": "^6.8.2", - "qw": "~1.0.1", - "read": "~1.0.7", - "read-cmd-shim": "^1.0.5", - "read-installed": "~4.0.3", - "read-package-json": "^2.1.1", - "read-package-tree": "^5.3.1", - "readable-stream": "^3.6.0", - "readdir-scoped-modules": "^1.1.0", - "request": "^2.88.0", - "retry": "^0.12.0", - "rimraf": "^2.7.1", - "safe-buffer": "^5.1.2", - "semver": "^5.7.1", - "sha": "^3.0.0", - "slide": "~1.1.6", - "sorted-object": "~2.0.1", - "sorted-union-stream": "~2.1.3", - "ssri": "^6.0.2", - "stringify-package": "^1.0.1", - "tar": "^4.4.19", - "text-table": "~0.2.0", - "tiny-relative-date": "^1.3.0", - "uid-number": "0.0.6", - "umask": "~1.1.0", - "unique-filename": "^1.1.1", - "unpipe": "~1.0.0", - "update-notifier": "^2.5.0", - "uuid": "^3.3.3", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "~3.0.0", - "which": "^1.3.1", - "worker-farm": "^1.7.0", - "write-file-atomic": "^2.4.3" - }, - "bin": { - "npm": "bin/npm-cli.js", - "npx": "bin/npx-cli.js" - }, - "engines": { - "node": "6 >=6.2.0 || 8 || >=9.3.0" - } - }, - "node_modules/npm-conf": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", - "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", - "dev": true, - "optional": true, - "dependencies": { - "config-chain": "^1.1.11", - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-conf/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "optional": true, - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/abbrev": { - "version": "1.1.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/agent-base": { - "version": "4.3.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/npm/node_modules/agentkeepalive": { - "version": "3.5.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/npm/node_modules/ansi-align": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "string-width": "^2.0.0" - } - }, - "node_modules/npm/node_modules/ansi-regex": { - "version": "2.1.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/ansi-styles": { - "version": "3.2.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/ansicolors": { - "version": "0.3.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/ansistyles": { - "version": "0.1.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/aproba": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/archy": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/are-we-there-yet": { - "version": "1.1.4", - "inBundle": true, - "license": "ISC", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "node_modules/npm/node_modules/are-we-there-yet/node_modules/readable-stream": { - "version": "2.3.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/npm/node_modules/are-we-there-yet/node_modules/string_decoder": { - "version": "1.1.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/npm/node_modules/asap": { - "version": "2.0.6", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/asn1": { - "version": "0.2.4", - "inBundle": true, - "license": "MIT", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/npm/node_modules/assert-plus": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/npm/node_modules/asynckit": { - "version": "0.4.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/aws-sign2": { - "version": "0.7.0", - "inBundle": true, - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/aws4": { - "version": "1.8.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/balanced-match": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "inBundle": true, - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/npm/node_modules/bin-links": { - "version": "1.1.8", - "inBundle": true, - "license": "Artistic-2.0", - "dependencies": { - "bluebird": "^3.5.3", - "cmd-shim": "^3.0.0", - "gentle-fs": "^2.3.0", - "graceful-fs": "^4.1.15", - "npm-normalize-package-bin": "^1.0.0", - "write-file-atomic": "^2.3.0" - } - }, - "node_modules/npm/node_modules/bluebird": { - "version": "3.5.5", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/boxen": { - "version": "1.3.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", - "term-size": "^1.2.0", - "widest-line": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/brace-expansion": { - "version": "1.1.11", - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/npm/node_modules/buffer-from": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/builtins": { - "version": "1.0.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/byline": { - "version": "5.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/byte-size": { - "version": "5.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/npm/node_modules/cacache": { - "version": "12.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - } - }, - "node_modules/npm/node_modules/call-limit": { - "version": "1.1.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/camelcase": { - "version": "4.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/capture-stack-trace": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/caseless": { - "version": "0.12.0", - "inBundle": true, - "license": "Apache-2.0" - }, - "node_modules/npm/node_modules/chalk": { - "version": "2.4.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/chownr": { - "version": "1.1.4", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/ci-info": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/cidr-regex": { - "version": "2.0.10", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "ip-regex": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/cli-boxes": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/cli-columns": { - "version": "3.1.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "string-width": "^2.0.0", - "strip-ansi": "^3.0.1" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/npm/node_modules/cli-table3": { - "version": "0.5.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "object-assign": "^4.1.0", - "string-width": "^2.1.1" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "colors": "^1.1.2" - } - }, - "node_modules/npm/node_modules/cliui": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "node_modules/npm/node_modules/cliui/node_modules/ansi-regex": { - "version": "4.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/cliui/node_modules/string-width": { - "version": "3.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/cliui/node_modules/strip-ansi": { - "version": "5.2.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/clone": { - "version": "1.0.4", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/npm/node_modules/cmd-shim": { - "version": "3.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "graceful-fs": "^4.1.2", - "mkdirp": "~0.5.0" - } - }, - "node_modules/npm/node_modules/code-point-at": { - "version": "1.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/color-convert": { - "version": "1.9.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "^1.1.1" - } - }, - "node_modules/npm/node_modules/color-name": { - "version": "1.1.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/colors": { - "version": "1.3.3", - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/npm/node_modules/columnify": { - "version": "1.5.4", - "inBundle": true, - "license": "MIT", - "dependencies": { - "strip-ansi": "^3.0.0", - "wcwidth": "^1.0.0" - } - }, - "node_modules/npm/node_modules/combined-stream": { - "version": "1.0.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/npm/node_modules/concat-map": { - "version": "0.0.1", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/concat-stream": { - "version": "1.6.2", - "engines": [ - "node >= 0.8" - ], - "inBundle": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/npm/node_modules/concat-stream/node_modules/readable-stream": { - "version": "2.3.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/npm/node_modules/concat-stream/node_modules/string_decoder": { - "version": "1.1.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/npm/node_modules/config-chain": { - "version": "1.1.12", - "inBundle": true, - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "node_modules/npm/node_modules/configstore": { - "version": "3.1.5", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "dot-prop": "^4.2.1", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/console-control-strings": { - "version": "1.1.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/copy-concurrently": { - "version": "1.0.5", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - } - }, - "node_modules/npm/node_modules/copy-concurrently/node_modules/aproba": { - "version": "1.2.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/copy-concurrently/node_modules/iferr": { - "version": "0.1.5", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/core-util-is": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/create-error-class": { - "version": "3.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "capture-stack-trace": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/cross-spawn": { - "version": "5.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "node_modules/npm/node_modules/cross-spawn/node_modules/lru-cache": { - "version": "4.1.5", - "inBundle": true, - "license": "ISC", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/npm/node_modules/cross-spawn/node_modules/yallist": { - "version": "2.1.2", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/crypto-random-string": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/cyclist": { - "version": "0.2.2", - "inBundle": true - }, - "node_modules/npm/node_modules/dashdash": { - "version": "1.14.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/npm/node_modules/debug": { - "version": "3.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/npm/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/debuglog": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/decamelize": { - "version": "1.2.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/decode-uri-component": { - "version": "0.2.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/npm/node_modules/deep-extend": { - "version": "0.6.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/npm/node_modules/defaults": { - "version": "1.0.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "clone": "^1.0.2" - } - }, - "node_modules/npm/node_modules/define-properties": { - "version": "1.1.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/npm/node_modules/delayed-stream": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/npm/node_modules/delegates": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/detect-indent": { - "version": "5.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/detect-newline": { - "version": "2.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/dezalgo": { - "version": "1.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "node_modules/npm/node_modules/dot-prop": { - "version": "4.2.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "is-obj": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/dotenv": { - "version": "5.0.1", - "inBundle": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.6.0" - } - }, - "node_modules/npm/node_modules/duplexer3": { - "version": "0.1.4", - "inBundle": true, - "license": "BSD-3-Clause" - }, - "node_modules/npm/node_modules/duplexify": { - "version": "3.6.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "node_modules/npm/node_modules/duplexify/node_modules/readable-stream": { - "version": "2.3.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/npm/node_modules/duplexify/node_modules/string_decoder": { - "version": "1.1.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/npm/node_modules/ecc-jsbn": { - "version": "0.1.2", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/npm/node_modules/editor": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/emoji-regex": { - "version": "7.0.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/encoding": { - "version": "0.1.12", - "inBundle": true, - "license": "MIT", - "dependencies": { - "iconv-lite": "~0.4.13" - } - }, - "node_modules/npm/node_modules/end-of-stream": { - "version": "1.4.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/npm/node_modules/env-paths": { - "version": "2.2.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/err-code": { - "version": "1.1.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/errno": { - "version": "0.1.7", - "inBundle": true, - "license": "MIT", - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, - "node_modules/npm/node_modules/es-abstract": { - "version": "1.12.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "es-to-primitive": "^1.1.1", - "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/npm/node_modules/es-to-primitive": { - "version": "1.2.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/npm/node_modules/es6-promise": { - "version": "4.2.8", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/es6-promisify": { - "version": "5.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "es6-promise": "^4.0.3" - } - }, - "node_modules/npm/node_modules/escape-string-regexp": { - "version": "1.0.5", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/npm/node_modules/execa": { - "version": "0.7.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/execa/node_modules/get-stream": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/extend": { - "version": "3.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/extsprintf": { - "version": "1.3.0", - "engines": [ - "node >=0.6.0" - ], - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/fast-json-stable-stringify": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/figgy-pudding": { - "version": "3.5.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/find-npm-prefix": { - "version": "1.0.2", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/flush-write-stream": { - "version": "1.0.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" - } - }, - "node_modules/npm/node_modules/flush-write-stream/node_modules/readable-stream": { - "version": "2.3.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/npm/node_modules/flush-write-stream/node_modules/string_decoder": { - "version": "1.1.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/npm/node_modules/forever-agent": { - "version": "0.6.1", - "inBundle": true, - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/form-data": { - "version": "2.3.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/npm/node_modules/from2": { - "version": "2.3.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "node_modules/npm/node_modules/from2/node_modules/readable-stream": { - "version": "2.3.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/npm/node_modules/from2/node_modules/string_decoder": { - "version": "1.1.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/npm/node_modules/fs-minipass": { - "version": "1.2.7", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^2.6.0" - } - }, - "node_modules/npm/node_modules/fs-minipass/node_modules/minipass": { - "version": "2.9.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "node_modules/npm/node_modules/fs-vacuum": { - "version": "1.2.10", - "inBundle": true, - "license": "ISC", - "dependencies": { - "graceful-fs": "^4.1.2", - "path-is-inside": "^1.0.1", - "rimraf": "^2.5.2" - } - }, - "node_modules/npm/node_modules/fs-write-stream-atomic": { - "version": "1.0.10", - "inBundle": true, - "license": "ISC", - "dependencies": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "node_modules/npm/node_modules/fs-write-stream-atomic/node_modules/iferr": { - "version": "0.1.5", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/fs-write-stream-atomic/node_modules/readable-stream": { - "version": "2.3.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/npm/node_modules/fs-write-stream-atomic/node_modules/string_decoder": { - "version": "1.1.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/npm/node_modules/fs.realpath": { - "version": "1.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/function-bind": { - "version": "1.1.1", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/gauge": { - "version": "2.7.4", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "node_modules/npm/node_modules/gauge/node_modules/aproba": { - "version": "1.2.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/gauge/node_modules/string-width": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/genfun": { - "version": "5.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/gentle-fs": { - "version": "2.3.1", - "inBundle": true, - "license": "Artistic-2.0", - "dependencies": { - "aproba": "^1.1.2", - "chownr": "^1.1.2", - "cmd-shim": "^3.0.3", - "fs-vacuum": "^1.2.10", - "graceful-fs": "^4.1.11", - "iferr": "^0.1.5", - "infer-owner": "^1.0.4", - "mkdirp": "^0.5.1", - "path-is-inside": "^1.0.2", - "read-cmd-shim": "^1.0.1", - "slide": "^1.1.6" - } - }, - "node_modules/npm/node_modules/gentle-fs/node_modules/aproba": { - "version": "1.2.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/gentle-fs/node_modules/iferr": { - "version": "0.1.5", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/get-caller-file": { - "version": "2.0.5", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/npm/node_modules/get-stream": { - "version": "4.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/getpass": { - "version": "0.1.7", - "inBundle": true, - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/npm/node_modules/glob": { - "version": "7.1.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/global-dirs": { - "version": "0.1.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ini": "^1.3.4" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/got": { - "version": "6.7.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/got/node_modules/get-stream": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/graceful-fs": { - "version": "4.2.4", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/har-schema": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/har-validator": { - "version": "5.1.5", - "deprecated": "this library is no longer supported", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/har-validator/node_modules/ajv": { - "version": "6.12.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/npm/node_modules/har-validator/node_modules/fast-deep-equal": { - "version": "3.1.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/har-validator/node_modules/json-schema-traverse": { - "version": "0.4.1", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/has": { - "version": "1.0.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/npm/node_modules/has-flag": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/has-symbols": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/npm/node_modules/has-unicode": { - "version": "2.0.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/hosted-git-info": { - "version": "2.8.9", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/http-cache-semantics": { - "version": "3.8.1", - "inBundle": true, - "license": "BSD-2-Clause" - }, - "node_modules/npm/node_modules/http-proxy-agent": { - "version": "2.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "4", - "debug": "3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/npm/node_modules/http-signature": { - "version": "1.2.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/npm/node_modules/https-proxy-agent": { - "version": "2.2.4", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/npm/node_modules/humanize-ms": { - "version": "1.2.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/npm/node_modules/iconv-lite": { - "version": "0.4.23", - "inBundle": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/iferr": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/npm/node_modules/ignore-walk": { - "version": "3.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minimatch": "^3.0.4" - } - }, - "node_modules/npm/node_modules/import-lazy": { - "version": "2.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/imurmurhash": { - "version": "0.1.4", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/npm/node_modules/infer-owner": { - "version": "1.0.4", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/inflight": { - "version": "1.0.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/npm/node_modules/inherits": { - "version": "2.0.4", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/ini": { - "version": "1.3.8", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/init-package-json": { - "version": "1.10.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.1", - "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", - "promzard": "^0.3.0", - "read": "~1.0.1", - "read-package-json": "1 || 2", - "semver": "2.x || 3.x || 4 || 5", - "validate-npm-package-license": "^3.0.1", - "validate-npm-package-name": "^3.0.0" - } - }, - "node_modules/npm/node_modules/ip": { - "version": "1.1.5", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/ip-regex": { - "version": "2.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/is-callable": { - "version": "1.1.4", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/npm/node_modules/is-ci": { - "version": "1.2.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ci-info": "^1.5.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/npm/node_modules/is-ci/node_modules/ci-info": { - "version": "1.6.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/is-cidr": { - "version": "3.0.0", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "cidr-regex": "^2.0.10" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/is-date-object": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/npm/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/is-installed-globally": { - "version": "0.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "global-dirs": "^0.1.0", - "is-path-inside": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/is-npm": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/is-obj": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/is-path-inside": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "path-is-inside": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/is-redirect": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/is-regex": { - "version": "1.0.4", - "inBundle": true, - "license": "MIT", - "dependencies": { - "has": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/npm/node_modules/is-retry-allowed": { - "version": "1.2.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/is-stream": { - "version": "1.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/is-symbol": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/npm/node_modules/is-typedarray": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/isarray": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/isexe": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/isstream": { - "version": "0.1.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/jsbn": { - "version": "0.1.1", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/npm/node_modules/json-parse-better-errors": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/json-schema": { - "version": "0.2.3", - "inBundle": true - }, - "node_modules/npm/node_modules/json-stringify-safe": { - "version": "5.0.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/jsonparse": { - "version": "1.3.1", - "engines": [ - "node >= 0.2.0" - ], - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/JSONStream": { - "version": "1.3.5", - "inBundle": true, - "license": "(MIT OR Apache-2.0)", - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/jsprim": { - "version": "1.4.1", - "engines": [ - "node >=0.6.0" - ], - "inBundle": true, - "license": "MIT", - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "node_modules/npm/node_modules/latest-version": { - "version": "3.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "package-json": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/lazy-property": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/libcipm": { - "version": "4.0.8", - "inBundle": true, - "license": "MIT", - "dependencies": { - "bin-links": "^1.1.2", - "bluebird": "^3.5.1", - "figgy-pudding": "^3.5.1", - "find-npm-prefix": "^1.0.2", - "graceful-fs": "^4.1.11", - "ini": "^1.3.5", - "lock-verify": "^2.1.0", - "mkdirp": "^0.5.1", - "npm-lifecycle": "^3.0.0", - "npm-logical-tree": "^1.2.1", - "npm-package-arg": "^6.1.0", - "pacote": "^9.1.0", - "read-package-json": "^2.0.13", - "rimraf": "^2.6.2", - "worker-farm": "^1.6.0" - } - }, - "node_modules/npm/node_modules/libnpm": { - "version": "3.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "bin-links": "^1.1.2", - "bluebird": "^3.5.3", - "find-npm-prefix": "^1.0.2", - "libnpmaccess": "^3.0.2", - "libnpmconfig": "^1.2.1", - "libnpmhook": "^5.0.3", - "libnpmorg": "^1.0.1", - "libnpmpublish": "^1.1.2", - "libnpmsearch": "^2.0.2", - "libnpmteam": "^1.0.2", - "lock-verify": "^2.0.2", - "npm-lifecycle": "^3.0.0", - "npm-logical-tree": "^1.2.1", - "npm-package-arg": "^6.1.0", - "npm-profile": "^4.0.2", - "npm-registry-fetch": "^4.0.0", - "npmlog": "^4.1.2", - "pacote": "^9.5.3", - "read-package-json": "^2.0.13", - "stringify-package": "^1.0.0" - } - }, - "node_modules/npm/node_modules/libnpmaccess": { - "version": "3.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "get-stream": "^4.0.0", - "npm-package-arg": "^6.1.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "node_modules/npm/node_modules/libnpmconfig": { - "version": "1.2.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "figgy-pudding": "^3.5.1", - "find-up": "^3.0.0", - "ini": "^1.3.5" - } - }, - "node_modules/npm/node_modules/libnpmconfig/node_modules/find-up": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/libnpmconfig/node_modules/locate-path": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/libnpmconfig/node_modules/p-limit": { - "version": "2.2.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/libnpmconfig/node_modules/p-locate": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/libnpmconfig/node_modules/p-try": { - "version": "2.2.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/libnpmhook": { - "version": "5.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "figgy-pudding": "^3.4.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "node_modules/npm/node_modules/libnpmorg": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "figgy-pudding": "^3.4.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "node_modules/npm/node_modules/libnpmpublish": { - "version": "1.1.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "figgy-pudding": "^3.5.1", - "get-stream": "^4.0.0", - "lodash.clonedeep": "^4.5.0", - "normalize-package-data": "^2.4.0", - "npm-package-arg": "^6.1.0", - "npm-registry-fetch": "^4.0.0", - "semver": "^5.5.1", - "ssri": "^6.0.1" - } - }, - "node_modules/npm/node_modules/libnpmsearch": { - "version": "2.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "figgy-pudding": "^3.5.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "node_modules/npm/node_modules/libnpmteam": { - "version": "1.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "figgy-pudding": "^3.4.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "node_modules/npm/node_modules/libnpx": { - "version": "10.2.4", - "inBundle": true, - "license": "ISC", - "dependencies": { - "dotenv": "^5.0.1", - "npm-package-arg": "^6.0.0", - "rimraf": "^2.6.2", - "safe-buffer": "^5.1.0", - "update-notifier": "^2.3.0", - "which": "^1.3.0", - "y18n": "^4.0.0", - "yargs": "^14.2.3" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/lock-verify": { - "version": "2.1.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-package-arg": "^6.1.0", - "semver": "^5.4.1" - } - }, - "node_modules/npm/node_modules/lockfile": { - "version": "1.0.4", - "inBundle": true, - "license": "ISC", - "dependencies": { - "signal-exit": "^3.0.2" - } - }, - "node_modules/npm/node_modules/lodash._baseindexof": { - "version": "3.1.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/lodash._baseuniq": { - "version": "4.6.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "lodash._createset": "~4.0.0", - "lodash._root": "~3.0.0" - } - }, - "node_modules/npm/node_modules/lodash._bindcallback": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/lodash._cacheindexof": { - "version": "3.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/lodash._createcache": { - "version": "3.1.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "lodash._getnative": "^3.0.0" - } - }, - "node_modules/npm/node_modules/lodash._createset": { - "version": "4.0.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/lodash._getnative": { - "version": "3.9.1", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/lodash._root": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/lodash.clonedeep": { - "version": "4.5.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/lodash.restparam": { - "version": "3.6.1", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/lodash.union": { - "version": "4.6.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/lodash.uniq": { - "version": "4.5.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/lodash.without": { - "version": "4.4.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/lowercase-keys": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/lru-cache": { - "version": "5.1.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/npm/node_modules/make-dir": { - "version": "1.3.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/make-fetch-happen": { - "version": "5.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "agentkeepalive": "^3.4.1", - "cacache": "^12.0.0", - "http-cache-semantics": "^3.8.1", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "node-fetch-npm": "^2.0.2", - "promise-retry": "^1.1.1", - "socks-proxy-agent": "^4.0.0", - "ssri": "^6.0.0" - } - }, - "node_modules/npm/node_modules/meant": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/mime-db": { - "version": "1.35.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/npm/node_modules/mime-types": { - "version": "2.1.19", - "inBundle": true, - "license": "MIT", - "dependencies": { - "mime-db": "~1.35.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/npm/node_modules/minimatch": { - "version": "3.0.4", - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/minimist": { - "version": "1.2.5", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/minizlib": { - "version": "1.3.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^2.9.0" - } - }, - "node_modules/npm/node_modules/minizlib/node_modules/minipass": { - "version": "2.9.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "node_modules/npm/node_modules/mississippi": { - "version": "3.0.0", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/npm/node_modules/mkdirp": { - "version": "0.5.5", - "inBundle": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/npm/node_modules/mkdirp/node_modules/minimist": { - "version": "1.2.5", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/move-concurrently": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } - }, - "node_modules/npm/node_modules/move-concurrently/node_modules/aproba": { - "version": "1.2.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/ms": { - "version": "2.1.1", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/mute-stream": { - "version": "0.0.7", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/node-fetch-npm": { - "version": "2.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "encoding": "^0.1.11", - "json-parse-better-errors": "^1.0.0", - "safe-buffer": "^5.1.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/node-gyp": { - "version": "5.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.2", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "npmlog": "^4.1.2", - "request": "^2.88.0", - "rimraf": "^2.6.3", - "semver": "^5.7.1", - "tar": "^4.4.12", - "which": "^1.3.1" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/npm/node_modules/nopt": { - "version": "4.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/npm/node_modules/normalize-package-data": { - "version": "2.5.0", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/npm/node_modules/normalize-package-data/node_modules/resolve": { - "version": "1.10.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "path-parse": "^1.0.6" - } - }, - "node_modules/npm/node_modules/npm-audit-report": { - "version": "1.3.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "cli-table3": "^0.5.0", - "console-control-strings": "^1.1.0" - } - }, - "node_modules/npm/node_modules/npm-bundled": { - "version": "1.1.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "node_modules/npm/node_modules/npm-cache-filename": { - "version": "1.0.2", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/npm-install-checks": { - "version": "3.0.2", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "semver": "^2.3.0 || 3.x || 4 || 5" - } - }, - "node_modules/npm/node_modules/npm-lifecycle": { - "version": "3.1.5", - "inBundle": true, - "license": "Artistic-2.0", - "dependencies": { - "byline": "^5.0.0", - "graceful-fs": "^4.1.15", - "node-gyp": "^5.0.2", - "resolve-from": "^4.0.0", - "slide": "^1.1.6", - "uid-number": "0.0.6", - "umask": "^1.1.0", - "which": "^1.3.1" - } - }, - "node_modules/npm/node_modules/npm-logical-tree": { - "version": "1.2.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/npm-package-arg": { - "version": "6.1.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^2.7.1", - "osenv": "^0.1.5", - "semver": "^5.6.0", - "validate-npm-package-name": "^3.0.0" - } - }, - "node_modules/npm/node_modules/npm-packlist": { - "version": "1.4.8", - "inBundle": true, - "license": "ISC", - "dependencies": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "node_modules/npm/node_modules/npm-pick-manifest": { - "version": "3.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "figgy-pudding": "^3.5.1", - "npm-package-arg": "^6.0.0", - "semver": "^5.4.1" - } - }, - "node_modules/npm/node_modules/npm-profile": { - "version": "4.0.4", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.1.2 || 2", - "figgy-pudding": "^3.4.1", - "npm-registry-fetch": "^4.0.0" - } - }, - "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "4.0.7", - "inBundle": true, - "license": "ISC", - "dependencies": { - "bluebird": "^3.5.1", - "figgy-pudding": "^3.4.1", - "JSONStream": "^1.3.4", - "lru-cache": "^5.1.1", - "make-fetch-happen": "^5.0.0", - "npm-package-arg": "^6.1.0", - "safe-buffer": "^5.2.0" - } - }, - "node_modules/npm/node_modules/npm-registry-fetch/node_modules/safe-buffer": { - "version": "5.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/npm-run-path": { - "version": "2.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/npm-user-validate": { - "version": "1.0.1", - "inBundle": true, - "license": "BSD-2-Clause" - }, - "node_modules/npm/node_modules/npmlog": { - "version": "4.1.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "node_modules/npm/node_modules/number-is-nan": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/oauth-sign": { - "version": "0.9.0", - "inBundle": true, - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/object-assign": { - "version": "4.1.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/object-keys": { - "version": "1.0.12", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/npm/node_modules/object.getownpropertydescriptors": { - "version": "2.0.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/npm/node_modules/once": { - "version": "1.4.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/npm/node_modules/opener": { - "version": "1.5.2", - "inBundle": true, - "license": "(WTFPL OR MIT)", - "bin": { - "opener": "bin/opener-bin.js" - } - }, - "node_modules/npm/node_modules/os-homedir": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/os-tmpdir": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/osenv": { - "version": "0.1.5", - "inBundle": true, - "license": "ISC", - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "node_modules/npm/node_modules/p-finally": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/package-json": { - "version": "4.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "got": "^6.7.1", - "registry-auth-token": "^3.0.1", - "registry-url": "^3.0.3", - "semver": "^5.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/pacote": { - "version": "9.5.12", - "inBundle": true, - "license": "MIT", - "dependencies": { - "bluebird": "^3.5.3", - "cacache": "^12.0.2", - "chownr": "^1.1.2", - "figgy-pudding": "^3.5.1", - "get-stream": "^4.1.0", - "glob": "^7.1.3", - "infer-owner": "^1.0.4", - "lru-cache": "^5.1.1", - "make-fetch-happen": "^5.0.0", - "minimatch": "^3.0.4", - "minipass": "^2.3.5", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "normalize-package-data": "^2.4.0", - "npm-normalize-package-bin": "^1.0.0", - "npm-package-arg": "^6.1.0", - "npm-packlist": "^1.1.12", - "npm-pick-manifest": "^3.0.0", - "npm-registry-fetch": "^4.0.0", - "osenv": "^0.1.5", - "promise-inflight": "^1.0.1", - "promise-retry": "^1.1.1", - "protoduck": "^5.0.1", - "rimraf": "^2.6.2", - "safe-buffer": "^5.1.2", - "semver": "^5.6.0", - "ssri": "^6.0.1", - "tar": "^4.4.10", - "unique-filename": "^1.1.1", - "which": "^1.3.1" - } - }, - "node_modules/npm/node_modules/pacote/node_modules/minipass": { - "version": "2.9.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "node_modules/npm/node_modules/parallel-transform": { - "version": "1.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "cyclist": "~0.2.2", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, - "node_modules/npm/node_modules/parallel-transform/node_modules/readable-stream": { - "version": "2.3.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/npm/node_modules/parallel-transform/node_modules/string_decoder": { - "version": "1.1.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/npm/node_modules/path-exists": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/path-is-absolute": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/path-is-inside": { - "version": "1.0.2", - "inBundle": true, - "license": "(WTFPL OR MIT)" - }, - "node_modules/npm/node_modules/path-key": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/path-parse": { - "version": "1.0.7", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/performance-now": { - "version": "2.1.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/pify": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/prepend-http": { - "version": "1.0.4", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/process-nextick-args": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/promise-inflight": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/promise-retry": { - "version": "1.1.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "err-code": "^1.0.0", - "retry": "^0.10.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/npm/node_modules/promise-retry/node_modules/retry": { - "version": "0.10.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/promzard": { - "version": "0.3.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "read": "1" - } - }, - "node_modules/npm/node_modules/proto-list": { - "version": "1.2.4", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/protoduck": { - "version": "5.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "genfun": "^5.0.0" - } - }, - "node_modules/npm/node_modules/prr": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/pseudomap": { - "version": "1.0.2", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/psl": { - "version": "1.1.29", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/pump": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/npm/node_modules/pumpify": { - "version": "1.5.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - } - }, - "node_modules/npm/node_modules/pumpify/node_modules/pump": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/npm/node_modules/punycode": { - "version": "1.4.1", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/qrcode-terminal": { - "version": "0.12.0", - "inBundle": true, - "bin": { - "qrcode-terminal": "bin/qrcode-terminal.js" - } - }, - "node_modules/npm/node_modules/qs": { - "version": "6.5.2", - "inBundle": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/npm/node_modules/query-string": { - "version": "6.8.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "decode-uri-component": "^0.2.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/qw": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/rc": { - "version": "1.2.8", - "inBundle": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/npm/node_modules/read": { - "version": "1.0.7", - "inBundle": true, - "license": "ISC", - "dependencies": { - "mute-stream": "~0.0.4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/npm/node_modules/read-cmd-shim": { - "version": "1.0.5", - "inBundle": true, - "license": "ISC", - "dependencies": { - "graceful-fs": "^4.1.2" - } - }, - "node_modules/npm/node_modules/read-installed": { - "version": "4.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "slide": "~1.1.3", - "util-extend": "^1.0.1" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.2" - } - }, - "node_modules/npm/node_modules/read-package-json": { - "version": "2.1.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.1", - "json-parse-better-errors": "^1.0.1", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.2" - } - }, - "node_modules/npm/node_modules/read-package-tree": { - "version": "5.3.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "util-promisify": "^2.1.0" - } - }, - "node_modules/npm/node_modules/readable-stream": { - "version": "3.6.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/npm/node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "node_modules/npm/node_modules/registry-auth-token": { - "version": "3.4.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/npm/node_modules/registry-url": { - "version": "3.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "rc": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/request": { - "version": "2.88.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/npm/node_modules/require-directory": { - "version": "2.1.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/require-main-filename": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/resolve-from": { - "version": "4.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/retry": { - "version": "0.12.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/npm/node_modules/rimraf": { - "version": "2.7.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/npm/node_modules/run-queue": { - "version": "1.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.1.1" - } - }, - "node_modules/npm/node_modules/run-queue/node_modules/aproba": { - "version": "1.2.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/safe-buffer": { - "version": "5.1.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/safer-buffer": { - "version": "2.1.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/semver": { - "version": "5.7.1", - "inBundle": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/npm/node_modules/semver-diff": { - "version": "2.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "semver": "^5.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/set-blocking": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/sha": { - "version": "3.0.0", - "inBundle": true, - "license": "(BSD-2-Clause OR MIT)", - "dependencies": { - "graceful-fs": "^4.1.2" - } - }, - "node_modules/npm/node_modules/shebang-command": { - "version": "1.2.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/shebang-regex": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/signal-exit": { - "version": "3.0.2", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/slide": { - "version": "1.1.6", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/smart-buffer": { - "version": "4.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/npm/node_modules/socks": { - "version": "2.3.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ip": "1.1.5", - "smart-buffer": "^4.1.0" - }, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "4.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "~4.2.1", - "socks": "~2.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/npm/node_modules/socks-proxy-agent/node_modules/agent-base": { - "version": "4.2.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/npm/node_modules/sorted-object": { - "version": "2.0.1", - "inBundle": true, - "license": "(WTFPL OR MIT)" - }, - "node_modules/npm/node_modules/sorted-union-stream": { - "version": "2.1.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "from2": "^1.3.0", - "stream-iterate": "^1.1.0" - } - }, - "node_modules/npm/node_modules/sorted-union-stream/node_modules/from2": { - "version": "1.3.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "inherits": "~2.0.1", - "readable-stream": "~1.1.10" - } - }, - "node_modules/npm/node_modules/sorted-union-stream/node_modules/isarray": { - "version": "0.0.1", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/sorted-union-stream/node_modules/readable-stream": { - "version": "1.1.14", - "inBundle": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/npm/node_modules/sorted-union-stream/node_modules/string_decoder": { - "version": "0.10.31", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/spdx-correct": { - "version": "3.0.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-exceptions": { - "version": "2.1.0", - "inBundle": true, - "license": "CC-BY-3.0" - }, - "node_modules/npm/node_modules/spdx-expression-parse": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.5", - "inBundle": true, - "license": "CC0-1.0" - }, - "node_modules/npm/node_modules/split-on-first": { - "version": "1.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/sshpk": { - "version": "1.14.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "dashdash": "^1.12.0", - "getpass": "^0.1.1", - "safer-buffer": "^2.0.2" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - }, - "optionalDependencies": { - "bcrypt-pbkdf": "^1.0.0", - "ecc-jsbn": "~0.1.1", - "jsbn": "~0.1.0", - "tweetnacl": "~0.14.0" - } - }, - "node_modules/npm/node_modules/ssri": { - "version": "6.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "figgy-pudding": "^3.5.1" - } - }, - "node_modules/npm/node_modules/stream-each": { - "version": "1.2.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "node_modules/npm/node_modules/stream-iterate": { - "version": "1.2.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "readable-stream": "^2.1.5", - "stream-shift": "^1.0.0" - } - }, - "node_modules/npm/node_modules/stream-iterate/node_modules/readable-stream": { - "version": "2.3.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/npm/node_modules/stream-iterate/node_modules/string_decoder": { - "version": "1.1.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/npm/node_modules/stream-shift": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/strict-uri-encode": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/string_decoder": { - "version": "1.3.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/npm/node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.2.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/string-width": { - "version": "2.1.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/string-width/node_modules/ansi-regex": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/string-width/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/string-width/node_modules/strip-ansi": { - "version": "4.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/stringify-package": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/strip-ansi": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/strip-eof": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/strip-json-comments": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/supports-color": { - "version": "5.4.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/tar": { - "version": "4.4.19", - "inBundle": true, - "license": "ISC", - "dependencies": { - "chownr": "^1.1.4", - "fs-minipass": "^1.2.7", - "minipass": "^2.9.0", - "minizlib": "^1.3.3", - "mkdirp": "^0.5.5", - "safe-buffer": "^5.2.1", - "yallist": "^3.1.1" - }, - "engines": { - "node": ">=4.5" - } - }, - "node_modules/npm/node_modules/tar/node_modules/minipass": { - "version": "2.9.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "node_modules/npm/node_modules/tar/node_modules/safe-buffer": { - "version": "5.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/tar/node_modules/yallist": { - "version": "3.1.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/term-size": { - "version": "1.2.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "execa": "^0.7.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/text-table": { - "version": "0.2.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/through": { - "version": "2.3.8", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/through2": { - "version": "2.0.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - }, - "node_modules/npm/node_modules/through2/node_modules/readable-stream": { - "version": "2.3.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/npm/node_modules/through2/node_modules/string_decoder": { - "version": "1.1.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/npm/node_modules/timed-out": { - "version": "4.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/tiny-relative-date": { - "version": "1.3.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/tough-cookie": { - "version": "2.4.3", - "inBundle": true, - "license": "BSD-3-Clause", - "dependencies": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/npm/node_modules/tunnel-agent": { - "version": "0.6.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/tweetnacl": { - "version": "0.14.5", - "inBundle": true, - "license": "Unlicense", - "optional": true - }, - "node_modules/npm/node_modules/typedarray": { - "version": "0.0.6", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/uid-number": { - "version": "0.0.6", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/umask": { - "version": "1.1.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/unique-filename": { - "version": "1.1.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/npm/node_modules/unique-slug": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - } - }, - "node_modules/npm/node_modules/unique-string": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "crypto-random-string": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/unpipe": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/npm/node_modules/unzip-response": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/update-notifier": { - "version": "2.5.0", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "boxen": "^1.2.1", - "chalk": "^2.0.1", - "configstore": "^3.0.0", - "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", - "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/uri-js": { - "version": "4.4.0", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/npm/node_modules/uri-js/node_modules/punycode": { - "version": "2.1.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/url-parse-lax": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "prepend-http": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/util-deprecate": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/util-extend": { - "version": "1.0.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/util-promisify": { - "version": "2.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "node_modules/npm/node_modules/uuid": { - "version": "3.3.3", - "inBundle": true, - "license": "MIT", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/npm/node_modules/validate-npm-package-license": { - "version": "3.0.4", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/npm/node_modules/validate-npm-package-name": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "builtins": "^1.0.3" - } - }, - "node_modules/npm/node_modules/verror": { - "version": "1.10.0", - "engines": [ - "node >=0.6.0" - ], - "inBundle": true, - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/npm/node_modules/wcwidth": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/npm/node_modules/which": { - "version": "1.3.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/npm/node_modules/which-module": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/wide-align": { - "version": "1.1.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2" - } - }, - "node_modules/npm/node_modules/wide-align/node_modules/string-width": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/widest-line": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "string-width": "^2.1.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/worker-farm": { - "version": "1.7.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "errno": "~0.1.7" - } - }, - "node_modules/npm/node_modules/wrap-ansi": { - "version": "5.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { - "version": "3.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "5.2.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/wrappy": { - "version": "1.0.2", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/write-file-atomic": { - "version": "2.4.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "node_modules/npm/node_modules/xdg-basedir": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/xtend": { - "version": "4.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/npm/node_modules/y18n": { - "version": "4.0.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/yallist": { - "version": "3.0.3", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/yargs": { - "version": "14.2.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "cliui": "^5.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^15.0.1" - } - }, - "node_modules/npm/node_modules/yargs-parser": { - "version": "15.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "node_modules/npm/node_modules/yargs-parser/node_modules/camelcase": { - "version": "5.3.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/yargs/node_modules/ansi-regex": { - "version": "4.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/yargs/node_modules/find-up": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/yargs/node_modules/locate-path": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/yargs/node_modules/p-limit": { - "version": "2.3.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/yargs/node_modules/p-locate": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/yargs/node_modules/p-try": { - "version": "2.2.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/yargs/node_modules/string-width": { - "version": "3.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/yargs/node_modules/strip-ansi": { - "version": "5.2.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dev": true, - "dependencies": { - "boolbase": "~1.0.0" - } - }, - "node_modules/num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", - "dev": true - }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "engines": { - "node": "*" - } - }, - "node_modules/object-assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", - "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-component": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", - "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", - "dev": true - }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.defaults": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", - "dev": true, - "dependencies": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.getownpropertydescriptors": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", - "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", - "dev": true, - "dependencies": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, - "dependencies": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.omit/node_modules/for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true, - "dependencies": { - "for-in": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.reduce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", - "dev": true, - "dependencies": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "dependencies": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "node_modules/optimist/node_modules/minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", - "dev": true - }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/optipng-bin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/optipng-bin/-/optipng-bin-6.0.0.tgz", - "integrity": "sha512-95bB4y8IaTsa/8x6QH4bLUuyvyOoGBCLDA7wOgDL8UFqJpSUh1Hob8JRJhit+wC1ZLN3tQ7mFt7KuBj0x8F2Wg==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "dependencies": { - "bin-build": "^3.0.0", - "bin-wrapper": "^4.0.0", - "logalot": "^2.0.0" - }, - "bin": { - "optipng": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ordered-read-streams": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", - "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.1" - } - }, - "node_modules/original": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", - "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", - "dependencies": { - "url-parse": "^1.4.3" - } - }, - "node_modules/os-filter-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz", - "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==", - "dev": true, - "optional": true, - "dependencies": { - "arch": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "dev": true, - "dependencies": { - "lcid": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-cancelable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", - "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-event": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-1.3.0.tgz", - "integrity": "sha1-jmtPT2XHK8W2/ii3XtqHT5akoIU=", - "dev": true, - "optional": true, - "dependencies": { - "p-timeout": "^1.1.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-is-promise": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", - "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-map-series": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-map-series/-/p-map-series-1.0.0.tgz", - "integrity": "sha1-v5j+V1cFZYqeE1G++4WuTB8Hvco=", - "dev": true, - "optional": true, - "dependencies": { - "p-reduce": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-pipe": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz", - "integrity": "sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-reduce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-timeout": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", - "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", - "dev": true, - "optional": true, - "dependencies": { - "p-finally": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module/node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-filepath": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", - "dev": true, - "dependencies": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "dependencies": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse-glob/node_modules/is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse-glob/node_modules/is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "dependencies": { - "is-extglob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", - "dev": true - }, - "node_modules/parseqs": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", - "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", - "dev": true, - "dependencies": { - "better-assert": "~1.0.0" - } - }, - "node_modules/parseuri": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", - "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", - "dev": true, - "dependencies": { - "better-assert": "~1.0.0" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "dependencies": { - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", - "dev": true, - "dependencies": { - "path-root-regex": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true, - "optional": true - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/plugin-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", - "dev": true, - "dependencies": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/plugin-error/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/plugin-error/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/plugin-error/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/plur": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/plur/-/plur-3.1.1.tgz", - "integrity": "sha512-t1Ax8KUvV3FFII8ltczPn2tJdjqbd1sIzu6t4JL7nQ3EyeL/lTrj5PWKb06ic5/6XYDr65rQ4uzQEGN70/6X5w==", - "dev": true, - "dependencies": { - "irregular-plurals": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dev": true, - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-calc": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", - "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", - "dev": true, - "dependencies": { - "postcss": "^7.0.27", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.2" - } - }, - "node_modules/postcss-colormin": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", - "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-colormin/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-convert-values": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", - "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-convert-values/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-discard-comments": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-discard-duplicates": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-discard-empty": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-discard-overridden": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-load-config": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz", - "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==", - "dev": true, - "dependencies": { - "cosmiconfig": "^5.0.0", - "import-cwd": "^2.0.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-merge-longhand": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", - "dev": true, - "dependencies": { - "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-merge-longhand/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-merge-rules": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "cssnano-util-same-parent": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0", - "vendors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-merge-rules/node_modules/postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "dependencies": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/postcss-minify-font-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-minify-font-values/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-minify-gradients": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", - "dev": true, - "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-minify-gradients/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-minify-params": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", - "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", - "dev": true, - "dependencies": { - "alphanum-sort": "^1.0.0", - "browserslist": "^4.0.0", - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "uniqs": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-minify-params/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-minify-selectors": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", - "dev": true, - "dependencies": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "dependencies": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/postcss-normalize-charset": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-display-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", - "dev": true, - "dependencies": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-display-values/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-positions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", - "dev": true, - "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-positions/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-repeat-style": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", - "dev": true, - "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-repeat-style/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-string": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", - "dev": true, - "dependencies": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-string/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-timing-functions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", - "dev": true, - "dependencies": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-timing-functions/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-unicode": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-unicode/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-url": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", - "dev": true, - "dependencies": { - "is-absolute-url": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-url/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-normalize-whitespace": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-whitespace/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-ordered-values": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", - "dev": true, - "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-ordered-values/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-reduce-initial": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-reduce-transforms": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", - "dev": true, - "dependencies": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-reduce-transforms/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-svgo": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz", - "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", - "dev": true, - "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-svgo/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - }, - "node_modules/postcss-unique-selectors": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", - "dev": true, - "dependencies": { - "alphanum-sort": "^1.0.0", - "postcss": "^7.0.0", - "uniqs": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", - "dev": true - }, - "node_modules/postcss/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, - "node_modules/postcss/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "dev": true, - "optional": true, - "dependencies": { - "asap": "~2.0.3" - } - }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" - }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true, - "optional": true - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "optional": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dev": true, - "dependencies": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - } - }, - "node_modules/pumpify/node_modules/pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "engines": { - "node": ">=6" - } - }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/qjobs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", - "dev": true, - "engines": { - "node": ">=0.9" - } - }, - "node_modules/qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/query-string": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", - "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", - "dependencies": { - "decode-uri-component": "^0.2.0", - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randomatic": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", - "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", - "dev": true, - "dependencies": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/randomatic/node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/randomatic/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "dev": true, - "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, - "optional": true, - "dependencies": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", - "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true - }, - "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "dev": true, - "dependencies": { - "is-equal-shallow": "^0.1.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true, - "engines": { - "node": ">=6.5.0" - } - }, - "node_modules/regexpu-core": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", - "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^9.0.0", - "regjsgen": "^0.5.2", - "regjsparser": "^0.7.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", - "dev": true - }, - "node_modules/regjsparser": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", - "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", - "dev": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/remove-bom-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", - "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5", - "is-utf8": "^0.2.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/remove-bom-stream": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", - "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", - "dev": true, - "dependencies": { - "remove-bom-buffer": "^3.0.0", - "safe-buffer": "^5.1.0", - "through2": "^2.0.3" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "node_modules/repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "optional": true, - "dependencies": { - "is-finite": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/replace-ext": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", - "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/replace-homedir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", - "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1", - "is-absolute": "^1.0.0", - "remove-trailing-separator": "^1.1.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "dependencies": { - "lodash": "^4.17.19" - }, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "request": "^2.34" - } - }, - "node_modules/request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "engines": { - "node": ">=0.12.0" - }, - "peerDependencies": { - "request": "^2.34" - } - }, - "node_modules/request-promise-native/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/request/node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/request/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" - }, - "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-options": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", - "dev": true, - "dependencies": { - "value-or-function": "^3.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "deprecated": "https://github.com/lydell/resolve-url#deprecated", - "dev": true - }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "dev": true, - "optional": true, - "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true - }, - "node_modules/rgb-regex": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", - "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", - "dev": true - }, - "node_modules/rgba-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", - "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", - "dev": true - }, - "node_modules/right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "dev": true, - "dependencies": { - "align-text": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/run-sequence": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/run-sequence/-/run-sequence-2.2.1.tgz", - "integrity": "sha512-qkzZnQWMZjcKbh3CNly2srtrkaO/2H/SI5f2eliMCapdRD3UhMrwjfOAZJAnZ2H8Ju4aBzFZkBGXUqFs9V0yxw==", - "dev": true, - "dependencies": { - "chalk": "^1.1.3", - "fancy-log": "^1.3.2", - "plugin-error": "^0.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/run-sequence/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/run-sequence/node_modules/arr-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", - "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", - "dev": true, - "dependencies": { - "arr-flatten": "^1.0.1", - "array-slice": "^0.2.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/run-sequence/node_modules/arr-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", - "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/run-sequence/node_modules/array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/run-sequence/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/run-sequence/node_modules/extend-shallow": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", - "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", - "dev": true, - "dependencies": { - "kind-of": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/run-sequence/node_modules/kind-of": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/run-sequence/node_modules/plugin-error": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", - "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", - "dev": true, - "dependencies": { - "ansi-cyan": "^0.1.1", - "ansi-red": "^0.1.1", - "arr-diff": "^1.0.1", - "arr-union": "^2.0.1", - "extend-shallow": "^1.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/run-sequence/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/run-sequence/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "dependencies": { - "ret": "~0.1.10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/seek-bzip": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", - "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==", - "dev": true, - "optional": true, - "dependencies": { - "commander": "^2.8.1" - }, - "bin": { - "seek-bunzip": "bin/seek-bunzip", - "seek-table": "bin/seek-bzip-table" - } - }, - "node_modules/select": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", - "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=" - }, - "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/semver-greatest-satisfied-range": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", - "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", - "dev": true, - "dependencies": { - "sver-compat": "^1.5.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/semver-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", - "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", - "dev": true, - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/semver-truncate": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-1.1.2.tgz", - "integrity": "sha1-V/Qd5pcHpicJp+AQS6IRcQnqR+g=", - "dev": true, - "optional": true, - "dependencies": { - "semver": "^5.3.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", - "dev": true - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", - "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", - "dev": true - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dev": true, - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "dev": true - }, - "node_modules/slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/socket.io": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", - "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", - "dev": true, - "dependencies": { - "debug": "~3.1.0", - "engine.io": "~3.2.0", - "has-binary2": "~1.0.2", - "socket.io-adapter": "~1.1.0", - "socket.io-client": "2.1.1", - "socket.io-parser": "~3.2.0" - } - }, - "node_modules/socket.io-adapter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", - "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==", - "dev": true - }, - "node_modules/socket.io-client": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", - "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", - "dev": true, - "dependencies": { - "backo2": "1.0.2", - "base64-arraybuffer": "0.1.5", - "component-bind": "1.0.0", - "component-emitter": "1.2.1", - "debug": "~3.1.0", - "engine.io-client": "~3.2.0", - "has-binary2": "~1.0.2", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "object-component": "0.0.3", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "socket.io-parser": "~3.2.0", - "to-array": "0.1.4" - } - }, - "node_modules/socket.io-client/node_modules/component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true - }, - "node_modules/socket.io-client/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/socket.io-client/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/socket.io-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", - "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", - "dev": true, - "dependencies": { - "component-emitter": "1.2.1", - "debug": "~3.1.0", - "isarray": "2.0.1" - } - }, - "node_modules/socket.io-parser/node_modules/component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true - }, - "node_modules/socket.io-parser/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/socket.io-parser/node_modules/isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", - "dev": true - }, - "node_modules/socket.io-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/socket.io/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/socket.io/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", - "dev": true, - "optional": true, - "dependencies": { - "is-plain-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sort-keys-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", - "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", - "dev": true, - "optional": true, - "dependencies": { - "sort-keys": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.20", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", - "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, - "node_modules/sparkles": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz", - "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==" - }, - "node_modules/spectrum-colorpicker2": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/spectrum-colorpicker2/-/spectrum-colorpicker2-2.0.8.tgz", - "integrity": "sha512-z8Wlww/SgRbMgwgljfPxA3HNJMRQ0PRKB9ef0bKVDB1EeSR+MsC0KuOjt9H/R/CdAIoBmvKJEfIAvWS4PQpL0Q==" - }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/squeak": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/squeak/-/squeak-1.3.0.tgz", - "integrity": "sha1-MwRQN7ZDiLVnZ0uEMiplIQc5FsM=", - "dev": true, - "optional": true, - "dependencies": { - "chalk": "^1.0.0", - "console-stream": "^0.1.1", - "lpad-align": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/squeak/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/squeak/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "optional": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/squeak/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "optional": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/squeak/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "dev": true - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stream-exhaust": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", - "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", - "dev": true - }, - "node_modules/stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", - "dev": true - }, - "node_modules/streamroller": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.6.tgz", - "integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==", - "dev": true, - "dependencies": { - "async": "^2.6.2", - "date-format": "^2.0.0", - "debug": "^3.2.6", - "fs-extra": "^7.0.1", - "lodash": "^4.17.14" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/streamroller/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "dependencies": { - "is-utf8": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-bom-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz", - "integrity": "sha1-+H217yYT9paKpUWr/h7HKLaoKco=", - "dev": true, - "dependencies": { - "first-chunk-stream": "^2.0.0", - "strip-bom": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-bom-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", - "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", - "dev": true, - "optional": true, - "dependencies": { - "is-natural-number": "^4.0.1" - } - }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, - "optional": true, - "dependencies": { - "get-stdin": "^4.0.1" - }, - "bin": { - "strip-indent": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-outer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", - "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", - "dev": true, - "optional": true, - "dependencies": { - "escape-string-regexp": "^1.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strnum": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.4.tgz", - "integrity": "sha512-lMzNMfDpaQOLt4B2mEbfzYS0+T7dvCXeojnlGf6f1AygvWDMcWyXYaLbyICfjVu29sErR8fnRagQfBW/N/hGgw==", - "dev": true, - "optional": true - }, - "node_modules/stylehacks": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", - "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/stylehacks/node_modules/postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "dependencies": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/sver-compat": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", - "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", - "dev": true, - "dependencies": { - "es6-iterator": "^2.0.1", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/svgo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "deprecated": "This SVGO version is no longer supported. Upgrade to v2.x.x.", - "dev": true, - "dependencies": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "dependencies": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/table/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "node_modules/table/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/table/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "dev": true, - "optional": true, - "dependencies": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/temp-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", - "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/tempfile": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-2.0.0.tgz", - "integrity": "sha1-awRGhWqbERTRhW/8vlCczLCXcmU=", - "dev": true, - "optional": true, - "dependencies": { - "temp-dir": "^1.0.0", - "uuid": "^3.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/terser": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz", - "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==", - "dev": true, - "dependencies": { - "commander": "^2.19.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.10" - }, - "bin": { - "terser": "bin/uglifyjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/terser/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", - "dev": true - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/through2-concurrent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/through2-concurrent/-/through2-concurrent-2.0.0.tgz", - "integrity": "sha512-R5/jLkfMvdmDD+seLwN7vB+mhbqzWop5fAjx5IX8/yQq7VhBhzDmhXgaHAOnhnWkCpRMM7gToYHycB0CS/pd+A==", - "dev": true, - "dependencies": { - "through2": "^2.0.0" - } - }, - "node_modules/through2-filter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", - "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", - "dev": true, - "dependencies": { - "through2": "~2.0.0", - "xtend": "~4.0.0" - } - }, - "node_modules/time-stamp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "dev": true, - "dependencies": { - "es5-ext": "~0.10.46", - "next-tick": "1" - } - }, - "node_modules/timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", - "dev": true - }, - "node_modules/tiny-emitter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" - }, - "node_modules/tinymce": { - "version": "4.9.11", - "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-4.9.11.tgz", - "integrity": "sha512-nkSLsax+VY5DBRjMFnHFqPwTnlLEGHCco82FwJF2JNH6W+5/ClvNC1P4uhD5lXPDNiDykSHR0XJdEh7w/ICHzA==" - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/to-absolute-glob": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", - "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", - "dev": true, - "dependencies": { - "is-absolute": "^1.0.0", - "is-negated-glob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-array": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", - "dev": true - }, - "node_modules/to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", - "dev": true, - "optional": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-through": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", - "dev": true, - "dependencies": { - "through2": "^2.0.3" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", - "dev": true, - "dependencies": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/trim-repeated": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", - "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", - "dev": true, - "optional": true, - "dependencies": { - "escape-string-regexp": "^1.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tryit": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", - "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", - "dev": true - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typeahead.js": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/typeahead.js/-/typeahead.js-0.11.1.tgz", - "integrity": "sha1-TmTmcbIjEKhgb0rsgFkkuoSwFbg=", - "dependencies": { - "jquery": ">=1.7" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "node_modules/uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "dev": true, - "dependencies": { - "source-map": "~0.5.1", - "yargs": "~3.10.0" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - }, - "optionalDependencies": { - "uglify-to-browserify": "~1.0.0" - } - }, - "node_modules/uglify-js/node_modules/camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uglify-js/node_modules/cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "dev": true, - "dependencies": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - } - }, - "node_modules/uglify-js/node_modules/wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/uglify-js/node_modules/yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dev": true, - "dependencies": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - }, - "node_modules/uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "dev": true, - "optional": true - }, - "node_modules/ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", - "dev": true - }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "dev": true, - "optional": true, - "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "node_modules/unc-path-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/underscore": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", - "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" - }, - "node_modules/undertaker": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", - "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "bach": "^1.0.0", - "collection-map": "^1.0.0", - "es6-weak-map": "^2.0.1", - "fast-levenshtein": "^1.0.0", - "last-run": "^1.1.0", - "object.defaults": "^1.0.0", - "object.reduce": "^1.0.0", - "undertaker-registry": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/undertaker-registry": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/undertaker/node_modules/fast-levenshtein": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", - "integrity": "sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=", - "dev": true - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, - "node_modules/uniqs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", - "dev": true - }, - "node_modules/unique-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", - "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", - "dev": true, - "dependencies": { - "json-stable-stringify-without-jsonify": "^1.0.1", - "through2-filter": "^3.0.0" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "deprecated": "Please see https://github.com/lydell/urix#deprecated", - "dev": true - }, - "node_modules/url-parse": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "dev": true, - "optional": true, - "dependencies": { - "prepend-http": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/url-to-options": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", - "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", - "dev": true, - "optional": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/useragent": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", - "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", - "dev": true, - "dependencies": { - "lru-cache": "4.1.x", - "tmp": "0.0.x" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", - "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/v8flags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/value-or-function": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", - "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vendors": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", - "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/verror/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "node_modules/vinyl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", - "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", - "dev": true, - "dependencies": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vinyl-bufferstream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/vinyl-bufferstream/-/vinyl-bufferstream-1.0.1.tgz", - "integrity": "sha1-BTeGn1gO/6TKRay0dXnkuf5jCBo=", - "dev": true, - "dependencies": { - "bufferstreams": "1.0.1" - } - }, - "node_modules/vinyl-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-2.0.0.tgz", - "integrity": "sha1-p+v1/779obfRjRQPyweyI++2dRo=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.3.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0", - "strip-bom-stream": "^2.0.0", - "vinyl": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/vinyl-file/node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/vinyl-file/node_modules/clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "node_modules/vinyl-file/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/vinyl-file/node_modules/replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/vinyl-file/node_modules/vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", - "dev": true, - "dependencies": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - }, - "engines": { - "node": ">= 0.9" - } - }, - "node_modules/vinyl-fs": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", - "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", - "dev": true, - "dependencies": { - "fs-mkdirp-stream": "^1.0.0", - "glob-stream": "^6.1.0", - "graceful-fs": "^4.0.0", - "is-valid-glob": "^1.0.0", - "lazystream": "^1.0.0", - "lead": "^1.0.0", - "object.assign": "^4.0.4", - "pumpify": "^1.3.5", - "readable-stream": "^2.3.3", - "remove-bom-buffer": "^3.0.0", - "remove-bom-stream": "^1.2.0", - "resolve-options": "^1.1.0", - "through2": "^2.0.0", - "to-through": "^2.0.0", - "value-or-function": "^3.0.0", - "vinyl": "^2.0.0", - "vinyl-sourcemap": "^1.1.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vinyl-sourcemap": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", - "dev": true, - "dependencies": { - "append-buffer": "^1.0.2", - "convert-source-map": "^1.5.0", - "graceful-fs": "^4.1.6", - "normalize-path": "^2.1.1", - "now-and-later": "^2.0.0", - "remove-bom-buffer": "^3.0.0", - "vinyl": "^2.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vinyl-sourcemap/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/vinyl-sourcemaps-apply": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", - "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", - "dev": true, - "dependencies": { - "source-map": "^0.5.1" - } - }, - "node_modules/void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "dependencies": { - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true, - "engines": { - "node": ">=10.4" - } - }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, - "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/when": { - "version": "3.7.8", - "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", - "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=", - "dev": true - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", - "dev": true - }, - "node_modules/wicg-inert": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/wicg-inert/-/wicg-inert-3.1.1.tgz", - "integrity": "sha512-PhBaNh8ur9Xm4Ggy4umelwNIP6pPP1bv3EaWaKqfb/QNme2rdLjm7wIInvV4WhxVHhzA4Spgw9qNSqWtB/ca2A==" - }, - "node_modules/window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "dependencies": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ws": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", - "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", - "dependencies": { - "async-limiter": "~1.0.0" - } - }, - "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "node_modules/xmlbuilder": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-12.0.0.tgz", - "integrity": "sha512-lMo8DJ8u6JRWp0/Y4XLa/atVDr75H9litKlb2E5j3V3MesoL50EBgZDWoLT3F/LztVnG67GjPXLZpqcky/UMnQ==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/xmlhttprequest-ssl": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", - "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", - "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", - "dev": true - }, - "node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "node_modules/yargs": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", - "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", - "dev": true, - "dependencies": { - "camelcase": "^3.0.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^1.4.0", - "read-pkg-up": "^1.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^1.0.2", - "which-module": "^1.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^5.0.1" - } - }, - "node_modules/yargs-parser": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", - "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", - "dev": true, - "dependencies": { - "camelcase": "^3.0.0", - "object.assign": "^4.1.0" - } - }, - "node_modules/yargs-parser/node_modules/camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yargs/node_modules/camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "dev": true, - "optional": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yeast": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", - "dev": true - } - }, + "lockfileVersion": 1, "dependencies": { "@babel/code-frame": { "version": "7.15.8", @@ -21506,8 +1060,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "acorn-walk": { "version": "7.2.0", @@ -21789,7 +1342,8 @@ "archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true }, "argh": { "version": "0.1.4", @@ -22081,7 +1635,8 @@ "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "base": { "version": "0.11.2", @@ -22468,7 +2023,8 @@ "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true }, "body-parser": { "version": "1.19.0", @@ -22529,6 +2085,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -23261,7 +2818,8 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "concat-stream": { "version": "1.6.2", @@ -23296,6 +2854,8 @@ "version": "1.1.13", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "optional": true, "requires": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -23414,7 +2974,8 @@ "core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true }, "cosmiconfig": { "version": "5.2.1", @@ -23761,7 +3322,8 @@ "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true }, "decompress": { "version": "4.2.1", @@ -23988,7 +3550,8 @@ "detect-newline": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=" + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true }, "di": { "version": "0.0.1", @@ -25579,7 +5142,8 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "fsevents": { "version": "1.2.13", @@ -25595,7 +5159,8 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "functional-red-black-tree": { "version": "1.0.1", @@ -25777,6 +5342,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -25988,7 +5554,8 @@ "graceful-fs": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "dev": true }, "growly": { "version": "1.3.0", @@ -26785,6 +6352,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -26924,7 +6492,8 @@ "hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true }, "hsl-regex": { "version": "1.0.0", @@ -27146,7 +6715,8 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true }, "indent-string": { "version": "2.1.0", @@ -27180,6 +6750,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -27188,12 +6759,14 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true }, "inquirer": { "version": "7.3.3", @@ -27434,6 +7007,7 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "dev": true, "requires": { "has": "^1.0.3" } @@ -27792,7 +7366,8 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true }, "isbinaryfile": { "version": "3.0.3", @@ -27806,7 +7381,8 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true }, "isobject": { "version": "3.0.1", @@ -27924,8 +7500,7 @@ "version": "7.5.5", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", - "dev": true, - "requires": {} + "dev": true } } }, @@ -27945,7 +7520,8 @@ "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true }, "json-schema": { "version": "0.2.3", @@ -28163,8 +7739,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/karma-jsdom-launcher/-/karma-jsdom-launcher-8.0.2.tgz", "integrity": "sha512-jxO+Nf9U/XNSnHXrNpxBbbMyeYuvJH1V++bRdZv20vJ9pvaLuQ6LFNIgn4hA1WAVmzMsvW9j0P2Q2hTLMWcSvw==", - "dev": true, - "requires": {} + "dev": true }, "karma-junit-reporter": { "version": "2.0.1", @@ -28385,7 +7960,8 @@ "lodash._getnative": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true }, "lodash._isiterateecall": { "version": "3.0.9", @@ -28494,7 +8070,8 @@ "lodash.restparam": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" + "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", + "dev": true }, "lodash.template": { "version": "4.5.0", @@ -28518,7 +8095,8 @@ "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true }, "log4js": { "version": "4.5.1", @@ -28607,6 +8185,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" @@ -28876,6 +8455,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -28883,7 +8463,8 @@ "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true }, "minimize": { "version": "2.2.0", @@ -28934,6 +8515,7 @@ "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, "requires": { "minimist": "^1.2.5" } @@ -29106,6 +8688,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, "requires": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -29150,6 +8733,7 @@ "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.15.tgz", "integrity": "sha512-dkcQc4n+DiJAMYG2haNAMyJbmuvevjXz+WC9dCUzodw8EovwTIc6CATSsTEplCY6c0jG4OshxFGFJsrnKJguWA==", "requires": { + "JSONStream": "^1.3.5", "abbrev": "~1.1.1", "ansicolors": "~0.3.2", "ansistyles": "~0.1.3", @@ -29190,7 +8774,6 @@ "init-package-json": "^1.10.3", "is-cidr": "^3.0.0", "json-parse-better-errors": "^1.0.2", - "JSONStream": "^1.3.5", "lazy-property": "~1.0.0", "libcipm": "^4.0.8", "libnpm": "^3.0.1", @@ -29275,6 +8858,14 @@ "write-file-atomic": "^2.4.3" }, "dependencies": { + "JSONStream": { + "version": "1.3.5", + "bundled": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, "abbrev": { "version": "1.1.1", "bundled": true @@ -30525,14 +10116,6 @@ "version": "1.3.1", "bundled": true }, - "JSONStream": { - "version": "1.3.5", - "bundled": true, - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, "jsprim": { "version": "1.4.1", "bundled": true, @@ -31072,9 +10655,9 @@ "version": "4.0.7", "bundled": true, "requires": { + "JSONStream": "^1.3.4", "bluebird": "^3.5.1", "figgy-pudding": "^3.4.1", - "JSONStream": "^1.3.4", "lru-cache": "^5.1.1", "make-fetch-happen": "^5.0.0", "npm-package-arg": "^6.1.0", @@ -31753,19 +11336,6 @@ "version": "2.0.0", "bundled": true }, - "string_decoder": { - "version": "1.3.0", - "bundled": true, - "requires": { - "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.0", - "bundled": true - } - } - }, "string-width": { "version": "2.1.1", "bundled": true, @@ -31791,6 +11361,19 @@ } } }, + "string_decoder": { + "version": "1.3.0", + "bundled": true, + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "bundled": true + } + } + }, "stringify-package": { "version": "1.0.1", "bundled": true @@ -32312,7 +11895,8 @@ "object-assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", - "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=" + "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=", + "dev": true }, "object-component": { "version": "0.0.3", @@ -32518,6 +12102,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1" } @@ -32814,7 +12399,8 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, "path-key": { "version": "2.0.1", @@ -32825,7 +12411,8 @@ "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true }, "path-root": { "version": "0.1.1", @@ -33497,7 +13084,8 @@ "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true }, "progress": { "version": "2.0.3", @@ -33518,7 +13106,9 @@ "proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true, + "optional": true }, "prr": { "version": "1.0.1", @@ -33530,7 +13120,8 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true }, "psl": { "version": "1.8.0", @@ -33598,6 +13189,8 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "optional": true, "requires": { "decode-uri-component": "^0.2.0", "object-assign": "^4.1.0", @@ -33702,6 +13295,7 @@ "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -34027,6 +13621,7 @@ "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, "requires": { "is-core-module": "^2.2.0", "path-parse": "^1.0.6" @@ -34126,6 +13721,7 @@ "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, "requires": { "glob": "^7.1.3" } @@ -34303,7 +13899,8 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true }, "semver-greatest-satisfied-range": { "version": "1.1.0", @@ -34776,6 +14373,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -34784,12 +14382,14 @@ "spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true }, "spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -34798,7 +14398,8 @@ "spdx-license-ids": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz", - "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==" + "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==", + "dev": true }, "spectrum-colorpicker2": { "version": "2.0.8", @@ -35053,15 +14654,9 @@ "strict-uri-encode": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true, + "optional": true }, "string-width": { "version": "4.2.3", @@ -35111,6 +14706,15 @@ "define-properties": "^1.1.3" } }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -35379,7 +14983,8 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true }, "through": { "version": "2.3.8", @@ -35885,7 +15490,8 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true }, "unquote": { "version": "1.1.1", @@ -35998,7 +15604,8 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true }, "util.promisify": { "version": "1.0.1", @@ -36042,6 +15649,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -36276,6 +15884,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, "requires": { "isexe": "^2.0.0" } @@ -36366,7 +15975,8 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "write": { "version": "1.0.3", @@ -36424,7 +16034,8 @@ "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true }, "yargs": { "version": "7.1.2", diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js index 0ac285c0949a..1b63dde26ceb 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js @@ -251,6 +251,7 @@ Use this directive to construct a header inside the main editor window. var iconPicker = { icon: scope.icon.split(' ')[0], color: scope.icon.split(' ')[1], + size: "medium", submit: function (model) { if (model.icon) { if (model.color) { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js index e1639dde26da..9bd190996051 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js @@ -35,9 +35,6 @@ // List of elements that can be focusable within the focus lock var focusableElementsSelector = '[role="button"], a[href]:not([disabled]):not(.ng-hide), button:not([disabled]):not(.ng-hide), textarea:not([disabled]):not(.ng-hide), input:not([disabled]):not(.ng-hide), select:not([disabled]):not(.ng-hide)'; - // Grab the body element so we can add the tabbing class on it when needed - var bodyElement = document.querySelector('body'); - function getDomNodes(){ infiniteEditorsWrapper = document.querySelector('.umb-editors'); if(infiniteEditorsWrapper) { @@ -47,7 +44,10 @@ function getFocusableElements(targetElm) { var elm = targetElm ? targetElm : target; - focusableElements = elm.querySelectorAll(focusableElementsSelector); + + // Filter out elements that are children of parents with the .ng-hide class + focusableElements = [...elm.querySelectorAll(focusableElementsSelector)].filter(elm => !elm.closest('.ng-hide')); + // Set first and last focusable elements firstFocusableElement = focusableElements[0]; lastFocusableElement = focusableElements[focusableElements.length - 1]; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbchildselector.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbchildselector.directive.js index 47441326d74a..7870267995dc 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbchildselector.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbchildselector.directive.js @@ -118,7 +118,7 @@ Use this directive to render a ui component for selecting child items to a paren (function() { 'use strict'; - function ChildSelectorDirective() { + function ChildSelectorDirective(overlayService, localizationService) { function link(scope, el, attr, ctrl) { @@ -126,10 +126,30 @@ Use this directive to render a ui component for selecting child items to a paren scope.dialogModel = {}; scope.showDialog = false; - scope.removeChild = (selectedChild, $index) => { - if (scope.onRemove) { - scope.onRemove(selectedChild, $index); - } + scope.removeChild = (selectedChild, $index, event) => { + const dialog = { + view: "views/components/overlays/umb-template-remove-confirm.html", + layout: selectedChild, + submitButtonLabelKey: "defaultdialogs_yesRemove", + submitButtonStyle: "danger", + submit: function () { + if(scope.onRemove) { + scope.onRemove(selectedChild, $index); + overlayService.close(); + } + }, + close: function () { + overlayService.close(); + } + }; + + localizationService.localize("general_delete").then(value => { + dialog.title = value; + overlayService.open(dialog); + }); + + event.preventDefault(); + event.stopPropagation(); }; scope.addChild = $event => { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js index 0fd6bba09106..44d45263dae5 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js @@ -933,12 +933,12 @@ } }; - scope.deleteProperty = (properties, { id, label }) => { - const propertyName = label || ""; + scope.deleteProperty = (properties, property) => { + const propertyName = property.label || ""; const localizeMany = localizationService.localizeMany(['general_delete']); - const localize = localizationService.localize('contentTypeEditor_confirmDeletePropertyMessage', [propertyName]); - + const localize = localizationService.localize('contentTypeEditor_confirmDeletePropertyMessage', [propertyName]); + $q.all([localizeMany, localize]).then(values => { const translations = values[0]; const message = values[1]; @@ -948,7 +948,7 @@ content: message, submitButtonLabelKey: 'actions_delete', submit: () => { - const index = properties.findIndex(property => property.id === id); + const index = properties.findIndex(p => property.id ? p.id === property.id : p === property); properties.splice(index, 1); notifyChanged(); diff --git a/src/Umbraco.Web.UI.Client/src/common/filters/umbCmsJoinArray.filter.js b/src/Umbraco.Web.UI.Client/src/common/filters/umbCmsJoinArray.filter.js index 870e49754105..05f83f96aa2e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/filters/umbCmsJoinArray.filter.js +++ b/src/Umbraco.Web.UI.Client/src/common/filters/umbCmsJoinArray.filter.js @@ -4,17 +4,20 @@ * @namespace umbCmsJoinArray * * param {array} array of string or objects, if an object use the third argument to specify which prop to list. - * param {seperator} string containing the seperator to add between joined values. + * param {separator} string containing the separator to add between joined values. * param {prop} string used if joining an array of objects, set the name of properties to join. * * @description - * Join an array of string or an array of objects, with a costum seperator. - * + * Join an array of string or an array of objects, with a custom separator. + * If the array is null or empty, returns an empty string + * If the array is not actually an array (ie a string or number), returns the value of the array */ angular.module("umbraco.filters").filter('umbCmsJoinArray', function () { return function join(array, separator, prop) { - return (!Utilities.isUndefined(prop) ? array.map(function (item) { - return item[prop]; - }) : array).join(separator || ''); + if (typeof array !== 'object' || !array) { + return array || ''; + } + separator = separator || ''; + return (!Utilities.isUndefined(prop) ? array.map(item => item[prop]) : array).join(separator); }; }); diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/entity.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/entity.mocks.js index 2c2007dd91b0..05594115e1d2 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/entity.mocks.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/entity.mocks.js @@ -34,6 +34,15 @@ angular.module('umbraco.mocks'). return [200, nodes, null]; } + function returnUrlsbyUdis(status, data, headers) { + + if (!mocksUtils.checkAuth()) { + return [401, null, null]; + } + + return [200, {}, null]; + } + function returnEntitybyIdsPost(method, url, data, headers) { if (!mocksUtils.checkAuth()) { @@ -73,6 +82,10 @@ angular.module('umbraco.mocks'). .whenPOST(mocksUtils.urlRegex('/umbraco/UmbracoApi/Entity/GetByIds')) .respond(returnEntitybyIdsPost); + $httpBackend + .whenPOST(mocksUtils.urlRegex('/umbraco/UmbracoApi/Entity/GetUrlsByUdis')) + .respond(returnUrlsbyUdis); + $httpBackend .whenGET(mocksUtils.urlRegex('/umbraco/UmbracoApi/Entity/GetAncestors')) .respond(returnEntitybyIds); diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js index 2dc6aeb6a672..c6dc313bc7fa 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js @@ -127,6 +127,21 @@ function entityResource($q, $http, umbRequestHelper) { 'Failed to retrieve url for id:' + id); }, + getUrlsByUdis: function(udis, culture) { + var query = "culture=" + (culture || ""); + + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "entityApiBaseUrl", + "GetUrlsByUdis", + query), + { + udis: udis + }), + 'Failed to retrieve url map for udis ' + udis); + }, + getUrlByUdi: function (udi, culture) { if (!udi) { diff --git a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js index cb06218618c6..4f5f47fb816b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js @@ -99,20 +99,21 @@ } } - /** * Generate label for Block, uses either the labelInterpolator or falls back to the contentTypeName. * @param {Object} blockObject BlockObject to recive data values from. */ function getBlockLabel(blockObject) { if (blockObject.labelInterpolator !== undefined) { - var labelVars = Object.assign({"$settings": blockObject.settingsData || {}, "$layout": blockObject.layout || {}, "$index": (blockObject.index || 0)+1 }, blockObject.data); - return blockObject.labelInterpolator(labelVars); + var labelVars = Object.assign({"$contentTypeName": blockObject.content.contentTypeName, "$settings": blockObject.settingsData || {}, "$layout": blockObject.layout || {}, "$index": (blockObject.index || 0)+1 }, blockObject.data); + var label = blockObject.labelInterpolator(labelVars); + if (label) { + return label; + } } return blockObject.content.contentTypeName; } - /** * Used to add watchers on all properties in a content or settings model */ diff --git a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js index b11e30f8e040..fe802a8a2872 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js @@ -214,17 +214,18 @@ When building a custom infinite editor view you can use the same components as a * Method to tell editors that they are begin blurred. */ function blur() { - - /* keyboard shortcuts will be overwritten by the new infinite editor + if (isEnabled === true) { + /* keyboard shortcuts will be overwritten by the new infinite editor so we need to store the shortcuts for the current editor so they can be rebound when the infinite editor closes */ - unbindKeyboardShortcuts(); - isEnabled = false; + unbindKeyboardShortcuts(); + isEnabled = false; + } } /** * @ngdoc method - * @name umbraco.services.editorService#blur + * @name umbraco.services.editorService#focus * @methodOf umbraco.services.editorService * * @description diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less index bdfc55f648d2..c3af6d4342ed 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-color-swatches.less @@ -22,6 +22,16 @@ box-shadow: 0 1px 3px fade(@black, 12%), 0 1px 2px fade(@black, 24%); } + &.umb-color-box--xs { + width: 27px; + height: 27px; + } + + &.umb-color-box--s { + width: 30px; + height: 30px; + } + &.umb-color-box--m { width: 40px; height: 40px; diff --git a/src/Umbraco.Web.UI.Client/src/less/dashboards/examine-management.less b/src/Umbraco.Web.UI.Client/src/less/dashboards/examine-management.less index 7b842c40ad38..533760149fcc 100644 --- a/src/Umbraco.Web.UI.Client/src/less/dashboards/examine-management.less +++ b/src/Umbraco.Web.UI.Client/src/less/dashboards/examine-management.less @@ -13,8 +13,45 @@ } } + .umb-panel-group__details-status-content{ + width:50%; // this is to fix flexbox not making the content too wide + } + .umb-panel-group__details-status-action{ background-color:transparent; padding-left:0; } + + .result-table { + overflow-x:auto; + border:1px solid @tableBorder; + + > table { + margin-bottom:0; + border:0; + } + + th:first-child, + td:first-child { + position:sticky; + left:0; + background-color:@white; + border-right:1px solid @tableBorder; + border-left:0; + + + td, + + th { + border-left:0; + } + } + + th:last-child, + td:last-child { + position:sticky; + right:0; + background-color:@white; + border-left:1px solid @tableBorder; + } + } } + diff --git a/src/Umbraco.Web.UI.Client/src/less/gridview.less b/src/Umbraco.Web.UI.Client/src/less/gridview.less index 80f13fbf1f79..83071a0d93ff 100644 --- a/src/Umbraco.Web.UI.Client/src/less/gridview.less +++ b/src/Umbraco.Web.UI.Client/src/less/gridview.less @@ -621,7 +621,6 @@ } .preview-rows { - display: inline-block; position: relative; box-sizing: border-box; @@ -675,9 +674,9 @@ } .preview-rows.columns { - min-height: 18px; + min-height: 16px; line-height: 11px; - padding: 1px; + padding: 0 1px 1px 1px; &.prevalues-rows { min-height: 30px; diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index f662bde936c9..fd699b79d0a9 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -622,6 +622,12 @@ justify-content: center; align-items: center; + > a { + display: block; + width: 100%; + height: 100%; + } + img { display: block; max-width: 100%; diff --git a/src/Umbraco.Web.UI.Client/src/less/utilities/_text-align.less b/src/Umbraco.Web.UI.Client/src/less/utilities/_text-align.less index beff81d80cba..070078fc19c2 100644 --- a/src/Umbraco.Web.UI.Client/src/less/utilities/_text-align.less +++ b/src/Umbraco.Web.UI.Client/src/less/utilities/_text-align.less @@ -2,6 +2,12 @@ TEXT ALIGN */ -.tl { text-align: left; } -.tr { text-align: right; } -.tc { text-align: center; } +.tl, +.table td.tl, +.table th.tl { text-align: left; } +.tr, +.table td.tr, +.table th.tr { text-align: right; } +.tc, +.table td.tc, +.table th.tc { text-align: center; } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js index d7d51539568b..439af502735d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dashboard.controller.js @@ -50,14 +50,17 @@ function DashboardController($scope, $q, $routeParams, $location, dashboardResou // Check the query parameter for a dashboard alias const dashboardAlias = $location.search()[DASHBOARD_QUERY_PARAM]; const dashboardIndex = $scope.dashboard.tabs.findIndex(tab => tab.alias === dashboardAlias); + const showDefaultDashboard = dashboardIndex === -1; // Set the first dashboard to active if there is no query parameter or we can't find a matching dashboard for the alias - const activeIndex = dashboardIndex !== -1 ? dashboardIndex : 0; + const activeIndex = showDefaultDashboard ? 0 : dashboardIndex; const tab = $scope.dashboard.tabs[activeIndex]; tab.active = true; - $location.search(DASHBOARD_QUERY_PARAM, tab.alias); + if (!showDefaultDashboard) { + $location.search(DASHBOARD_QUERY_PARAM, tab.alias); + } } } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.html index 41bf92b27e8e..837aa43cc3af 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.html @@ -28,12 +28,12 @@ -
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.html index 49d40efffaa3..0e936e52c427 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.html @@ -28,12 +28,12 @@

  • - +
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-group.html b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-group.html index e75f30d7ebdd..35b3eb73534f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-group.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-group.html @@ -3,7 +3,10 @@
- + +
- + : {{ vm.group.inheritedFromName }} @@ -52,7 +55,7 @@
- +
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-property.html b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-property.html index 5724aa4e2e4c..8751a4723fe5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-property.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-property.html @@ -46,7 +46,7 @@
- + {{ vm.property.label }} ({{ vm.property.alias }}) @@ -65,32 +65,32 @@
- * + *
- +
- +
- +
- +
- +
@@ -99,13 +99,13 @@
- + {{vm.property.contentTypeName}}
- +
@@ -119,7 +119,7 @@ - +
@@ -130,15 +130,15 @@
-
-
@@ -146,4 +146,4 @@
-
\ No newline at end of file + diff --git a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-tab.html b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-tab.html index ada6273217d5..59476f7e26c6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-tab.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-tab.html @@ -19,8 +19,14 @@
- - + + + +
{{ vm.tab.name }}
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/overlays/umb-template-remove-confirm.html b/src/Umbraco.Web.UI.Client/src/views/components/overlays/umb-template-remove-confirm.html new file mode 100644 index 000000000000..17b853fcbc15 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/components/overlays/umb-template-remove-confirm.html @@ -0,0 +1,15 @@ +
+ +
+ You are removing the child node {{model.layout.name}}. +
+ +

+ + Removing a child node will limit the editors options to create different content types beneath a node. + +

+ + Are you sure you want to remove? + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-child-selector.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-child-selector.html index 47b2f96ba577..c7c8db041bcc 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-child-selector.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-child-selector.html @@ -24,8 +24,8 @@ {{selectedChild.name}}
-
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/content.createblueprint.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/content.createblueprint.controller.js index afd844aa0169..9dc1b6cefd92 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/content.createblueprint.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/content.createblueprint.controller.js @@ -12,7 +12,7 @@ name: $scope.currentNode.name }; - localizationService.localize("blueprints_createBlueprintFrom", ["" + $scope.message.name + ""]).then(function (localizedVal) { + localizationService.localize("blueprints_createBlueprintFrom", [$scope.message.name]).then(localizedVal => { $scope.title = localizedVal; }); @@ -33,14 +33,13 @@ navigationService.hideMenu(); }, - function (err) { - formHelper.resetForm({ scope: $scope, hasErrors: true }); - contentEditingHelper.handleSaveError({ - err: err - }); - - } - ); + function (err) { + formHelper.resetForm({ scope: $scope, hasErrors: true }); + contentEditingHelper.handleSaveError({ + err: err + }); + + }); } }; } diff --git a/src/Umbraco.Web.UI.Client/src/views/content/copy.html b/src/Umbraco.Web.UI.Client/src/views/content/copy.html index 399e0b8bf0e3..167e67431b7c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/copy.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/copy.html @@ -85,10 +85,10 @@ diff --git a/src/Umbraco.Web.UI.Client/src/views/content/createblueprint.html b/src/Umbraco.Web.UI.Client/src/views/content/createblueprint.html index 034a123e9b5e..7a1c8c381ebe 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/createblueprint.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/createblueprint.html @@ -18,7 +18,7 @@
- + Required {{blueprintForm.name.errorMsg}} diff --git a/src/Umbraco.Web.UI.Client/src/views/contentBlueprints/create.html b/src/Umbraco.Web.UI.Client/src/views/contentBlueprints/create.html index 332b27c81b0a..f58c330ce928 100644 --- a/src/Umbraco.Web.UI.Client/src/views/contentBlueprints/create.html +++ b/src/Umbraco.Web.UI.Client/src/views/contentBlueprints/create.html @@ -12,7 +12,7 @@
Create an item under {{current
    -
  • +
  • + {{ ::result.values['nodeName'] | umbCmsJoinArray:', '}} + {{ ::result.values['nodeName'] | umbCmsJoinArray:', '}} + @@ -288,27 +288,52 @@

    - - - - - - - - - - - - - - - - -
    ScoreIdName
    {{result.score}}{{result.id}} - {{result.values['nodeName'] | umbCmsJoinArray:', '}} - {{result.values['nodeName'] | umbCmsJoinArray:', '}} - -
    +
    + + + + + + + + + + + + + + + + + + + +
    IdName +
    + {{ field }} + +
    +
    + + Score
    {{result.id}} + + {{ ::result.values['nodeName'] | umbCmsJoinArray:', ' }} + + {{ ::result.values['nodeName'] | umbCmsJoinArray:', ' }} + + {{ ::result.values[field] | umbCmsJoinArray:', ' }} + + + + + {{ ::result.score | number:4 }} + +
    +
    + + + + + + +
    + + + + + {{ field }} +
    +
    +
    +
    + + + + + + +
    +
    diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagementresults.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagementresults.html index cd455a32ae16..ad888cfcf3fe 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagementresults.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagementresults.html @@ -20,7 +20,7 @@ {{key}} - {{values | umbCmsJoinArray:', '}} + {{ ::values | umbCmsJoinArray:', '}} diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/publishedsnapshotcache.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/publishedsnapshotcache.html index e1f95ad62da3..5640b23ded1b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/publishedsnapshotcache.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/publishedsnapshotcache.html @@ -1,11 +1,8 @@ 
    -
    +
    -

    - (wait) -

    diff --git a/src/Umbraco.Web.UI.Client/src/views/dataTypes/create.html b/src/Umbraco.Web.UI.Client/src/views/dataTypes/create.html index 5a7859add901..e78e70092b24 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dataTypes/create.html +++ b/src/Umbraco.Web.UI.Client/src/views/dataTypes/create.html @@ -1,54 +1,70 @@
    -
Du installerede Runway, så hvorfor ikke se hvordan dit nye website ser ud.]]> - Yderligere hjælpe og informationer Få hjælp fra vores prisvindende fællesskab, gennemse dokumentationen eller se nogle gratis videoer om hvordan du opsætter et simpelt site, hvordan du bruger pakker og en 'quick guide' til Umbraco terminologier]]> + + Gennemse dit nye site Du installerede Runway, så hvorfor ikke se hvordan dit nye website ser ud.]]> + + Yderligere hjælpe og informationer Få hjælp fra vores prisvindende fællesskab, gennemse dokumentationen eller se nogle gratis videoer om hvordan du opsætter et simpelt site, hvordan du bruger pakker og en 'quick guide' til Umbraco terminologier]]> Umbraco %0% er installeret og klar til brug + + /web.config filen og opdatére 'AppSetting' feltet UmbracoConfigurationStatus i bunden til '%0%'.]]> komme igang med det samme ved at klikke på "Start Umbraco" knappen nedenfor.
Hvis du er ny med Umbraco, kan du finde masser af ressourcer på vores 'getting started' sider. ]]>
- Start UmbracoFor at administrere dit website skal du blot åbne Umbraco administrationen og begynde at tilføje indhold, opdatere skabelonerne og stylesheets'ene eller tilføje ny funktionalitet.]]> + + Start UmbracoFor at administrere dit website skal du blot åbne Umbraco administrationen og begynde at tilføje indhold, opdatere skabelonerne og stylesheets'ene eller tilføje ny funktionalitet.]]> Forbindelse til databasen fejlede. Umbraco Version 3 Umbraco Version 4 Se - Umbraco %0% for en frisk installation eller for en opgradering fra version 3.0.

Tryk på Næste for at begynde på guiden.]]>
+ + Umbraco %0% for en frisk installation eller for en opgradering fra version 3.0.

Tryk på Næste for at begynde på guiden.]]>
Culture Code @@ -896,10 +1009,15 @@ Log ind nedenfor Log ind med Din session er udløbet - © 2001 - %0%
umbraco.com

]]>
+ + © 2001 - %0%
umbraco.com

]]>
Glemt adgangskode? - En e-mail vil blive sendt til den angivne adresse med et link til at nulstille din adgangskode - En e-mail med instruktioner for nulstilling af adgangskoden vil blive sendt til den angivne adresse, hvis det matcher vores optegnelser + En e-mail vil blive sendt til den angivne adresse med et link til at + nulstille din adgangskode + + En e-mail med instruktioner for nulstilling af adgangskoden vil blive + sendt til den angivne adresse, hvis det matcher vores optegnelser + Vis adgangskode Skjul adgangskode Tilbage til login formular @@ -907,7 +1025,8 @@ Din adgangskode er blevet opdateret Det link, du har klikket på, er ugyldigt eller udløbet Umbraco: Nulstil adgangskode - Dit brugernavn til at logge på Umbraco backoffice er: %0%

Klik her for at nulstille din adgangskode eller kopier/indsæt denne URL i din browser:

%1%

]]>
+ + Dit brugernavn til at logge på Umbraco backoffice er: %0%

Klik her for at nulstille din adgangskode eller kopier/indsæt denne URL i din browser:

%1%

]]>
Skrivebord @@ -925,7 +1044,9 @@ Det nuværende element kan ikke lægges under denne pga. sin type Det nuværende element kan ikke ligge under en af dens undersider Dette element må ikke findes på rodniveau - Denne handling er ikke tilladt fordi du ikke har de fornødne rettigheder på et eller flere af under-dokumenterne + Denne handling er ikke tilladt fordi du ikke har de fornødne rettigheder på et eller flere af + under-dokumenterne + Relater det kopierede element til originalen @@ -964,13 +1085,15 @@ Mange hilsner fra Umbraco robotten Denne pakke har ingen konfigurationsvisning Der er ikke blevet oprettet nogle pakker endnu Du har ingen pakker installeret - 'Pakker' øverst til højre på din skærm]]> + + 'Pakker' øverst til højre på din skærm]]> Pakkeindhold Licens Søg efter pakker Resultater for Vi kunne ikke finde resultater for - Prøv venligst at søge efter en anden pakke eller gennemse kategorierne + Prøv venligst at søge efter en anden pakke eller gennemse kategorierne + Populære Nye udgivelser har @@ -984,14 +1107,18 @@ Mange hilsner fra Umbraco robotten Downloads Likes Kompatibilitet - Denne pakke er kompatibel med de følgende versioner af Umbraco, som rapporteret af community-medlemmer. Fuld kompatibilitet kan ikke garanteres for versioner rapporteret nedenfor 100% + Denne pakke er kompatibel med de følgende versioner af Umbraco, som + rapporteret af community-medlemmer. Fuld kompatibilitet kan ikke garanteres for versioner rapporteret nedenfor + 100% + Eksterne kilder Forfatter Dokumentation Pakke meta data Pakkenavn Pakken indeholder ingen elementer -
Du kan roligt fjerne denne fra systemet ved at klikke på "Fjern pakke" nedenfor.]]>
+ +
Du kan roligt fjerne denne fra systemet ved at klikke på "Fjern pakke" nedenfor.]]>
Pakkevalg Pakke læs mig Pakke opbevaringsbase @@ -1005,9 +1132,13 @@ Mange hilsner fra Umbraco robotten Indsæt med fuld formattering (Anbefales ikke) - Den tekst du er ved at indsætte indeholder specialtegn eller formattering. Dette kan skyldes at du kopierer fra f.eks. Microsoft Word. Umbraco kan fjerne denne specialformattering automatisk så indholdet er mere velegnet til visning på en webside. + Den tekst du er ved at indsætte indeholder specialtegn eller formattering. Dette kan + skyldes at du kopierer fra f.eks. Microsoft Word. Umbraco kan fjerne denne specialformattering automatisk så + indholdet er mere velegnet til visning på en webside. + Indsæt som ren tekst, dvs. fjern al formattering - Indsæt, men fjern formattering som ikke bør være på en webside (Anbefales) + Indsæt, men fjern formattering som ikke bør være på en webside (Anbefales) + Gruppebaseret beskyttelse @@ -1021,7 +1152,8 @@ Mange hilsner fra Umbraco robotten Log ind-side Vælg siden der indeholder log ind-formularen Fjern beskyttelse... - %0%?]]> + + %0%?]]> Vælg siderne der indeholder log ind-formularer og fejlmeddelelser %0%]]> %0%]]> @@ -1041,7 +1173,8 @@ Mange hilsner fra Umbraco robotten - %0% kunne ikke udgives, fordi et 3. parts modul annullerede handlingen + %0% kunne ikke udgives, fordi et 3. parts modul annullerede handlingen + Medtag ikke-udgivede undersider Publicerer - vent venligst... @@ -1049,7 +1182,8 @@ Mange hilsner fra Umbraco robotten %0% er nu publiceret %0% og alle undersider er nu publiceret Publicér alle undersider - ok for at udgive %0% og derved gøre indholdet offentligt tilgængeligt..

Du kan udgive denne side og dens undersider ved at klikke Udgiv alle undersider forneden]]>
+ + ok for at udgive %0% og derved gøre indholdet offentligt tilgængeligt..

Du kan udgive denne side og dens undersider ved at klikke Udgiv alle undersider forneden]]>
Du har ikke konfigureret nogen godkendte farver @@ -1068,8 +1202,11 @@ Mange hilsner fra Umbraco robotten Skift medie Rediger %0% på %1% Annuller indsættelse? - - Du har foretaget ændringer til bruge af dette media. Er du sikker på at du vil annullere? + + + Du har foretaget ændringer til bruge af dette media. Er du sikker på + at du vil annullere? + Fjern brugen af alle medier? Udklipsholder Ikke tilladt @@ -1094,9 +1231,12 @@ Mange hilsner fra Umbraco robotten Oprettet Vælg en version at sammenligne med den nuværende version Nuværende version - Rød tekst vil ikke blive vist i den valgte version. Grøn betyder tilføjet]]> + + Rød tekst vil ikke blive vist i den valgte version. Grøn betyder tilføjet]]> Dokument tilbagerullet - Her vises den valgte version som html. Hvis du ønsker at se forskellen mellem de 2 versioner på samme tid, brug 'diff'-oversigten + Her vises den valgte version som html. Hvis du ønsker at se forskellen mellem de 2 versioner + på samme tid, brug 'diff'-oversigten + Tilbagerulning til Vælg version Vis @@ -1129,7 +1269,9 @@ Mange hilsner fra Umbraco robotten Standardskabelon - For at importere en dokumenttype, find ".udt"-filen på din computer ved at klikke på "Gennemse"-knappen og klik "Import" (Du vil blive bedt om bekræftelse på næste skærmbillede) + For at importere en dokumenttype, find ".udt"-filen på din computer ved at + klikke på "Gennemse"-knappen og klik "Import" (Du vil blive bedt om bekræftelse på næste skærmbillede) + Ny titel på faneblad Nodetype Type @@ -1145,7 +1287,9 @@ Mange hilsner fra Umbraco robotten Sorteringsrækkefølge Oprettelsesdato Sortering udført - Træk de forskellige sider op eller ned for at indstille hvordan de skal arrangeres, eller klik på kolonnehovederne for at sortere hele rækken af sider + Træk de forskellige sider op eller ned for at indstille hvordan de skal arrangeres, eller klik + på kolonnehovederne for at sortere hele rækken af sider + Denne node har ingen under noder at sortere @@ -1211,7 +1355,9 @@ Mange hilsner fra Umbraco robotten Skabelon gemt uden fejl! Indhold fjernet fra udgivelse Indhold variation %0% afpubliceret - Det krævet sprog '%0%' var afpubliceret. Alle sprog for dette indholds element er nu afpubliceret. + Det krævet sprog '%0%' var afpubliceret. Alle sprog for dette + indholds element er nu afpubliceret. + Partial view gemt Partial view gemt uden fejl! Partial view ikke gemt @@ -1236,18 +1382,26 @@ Mange hilsner fra Umbraco robotten Dokumenttypen blev eksporteret til en fil Der skete en fejl under eksport af en dokumenttype Udgivelses datoen kan ikke ligge i fortiden - Kan ikke planlægge dokumentes udgivelse da det krævet '%0%' ikke er udgivet - Kan ikke planlægge dokumentes udgivelse da det krævet '%0%' har en senere udgivelses dato end et ikke krævet sprog + Kan ikke planlægge dokumentes udgivelse da det krævet '%0%' ikke er udgivet + + Kan ikke planlægge dokumentes udgivelse da det krævet '%0%' har en senere + udgivelses dato end et ikke krævet sprog + Afpubliceringsdatoen kan ikke ligge i fortiden Afpubliceringsdatoen kan ikke være før udgivelsesdatoen - Domæner er ikke konfigureret for en flersproget side, kontakt vensligst en administrator, se loggen for mere information - Der er ikke noget domæne konfigureret for %0%, kontakt vensligst en administrator, se loggen for mere information + Domæner er ikke konfigureret for en flersproget side, kontakt vensligst en + administrator, se loggen for mere information + + Der er ikke noget domæne konfigureret for %0%, kontakt vensligst en + administrator, se loggen for mere information + Tilføj style Redigér style Teksteditor-styles - Definér de styles, der skal være tilgængelige i teksteditoren for dette stylesheet + Definér de styles, der skal være tilgængelige i teksteditoren for dette stylesheet + Selector Bruger CSS-syntaks, f.eks. "h1" eller ".redheader" Rediger stylesheet @@ -1269,7 +1423,9 @@ Mange hilsner fra Umbraco robotten Indsæt Hvad vil du indsætte? Oversættelse - Indsætter en oversætbar tekst, som skifter efter det sprog, som websitet vises i. + Indsætter en oversætbar tekst, som skifter efter det sprog, som websitet vises + i. + Makro En makro er et element, som kan have forskellige indstillinger, når det indsættes. @@ -1357,15 +1513,19 @@ Mange hilsner fra Umbraco robotten Klik for at indsætte et billede Skriv her... Grid layout - Et layout er det overordnede arbejdsområde til dit grid - du vil typisk kun behøve ét eller to + Et layout er det overordnede arbejdsområde til dit grid - du vil typisk kun behøve ét + eller to + Tilføj grid layout Rediger grid layout - Juster dit layout ved at justere kolonnebredder og tilføj yderligere sektioner + Juster dit layout ved at justere kolonnebredder og tilføj yderligere sektioner + Rækkekonfigurationer Rækker er foruddefinerede celler, der arrangeres vandret Tilføj rækkekonfiguration Rediger rækkekonfiguration - Juster rækken ved at indstille cellebredder og tilføje yderligere celler + Juster rækken ved at indstille cellebredder og tilføje yderligere celler + Ingen yderligere konfiguration tilgængelig Kolonner Det totale antal kolonner i dit grid @@ -1380,7 +1540,13 @@ Mange hilsner fra Umbraco robotten Vælg standard er tilføjet Du sletter en rækkekonfiguration - Sletning af et rækkekonfigurations navn vil resultere i et tab af data for alle eksiterende indhold som bruger dens konfiguration. + Sletning af et rækkekonfigurations navn vil resultere i et tab af data for alle + eksiterende indhold som bruger dens konfiguration. + + Du sletter et layoutet + Når du redigerer et layout vil data gå tabt de steder, hvor denne konfiguration + bruges. + Maksimalt emner Efterlad blank eller sæt til 0 for ubegrænset @@ -1393,18 +1559,28 @@ Mange hilsner fra Umbraco robotten Tilføj egenskab Påkrævet label Aktivér listevisning - Konfigurér indholdet til at blive vist i en sortérbar og søgbar liste; undersider vil ikke blive vist i træet + Konfigurér indholdet til at blive vist i en sortérbar og søgbar liste; + undersider vil ikke blive vist i træet + Tilladte skabeloner Vælg hvilke skabeloner, der er tilladt at bruge på dette indhold. Tillad på rodniveau - Kun dokumenttyper med denne indstilling aktiveret kan oprettes i rodniveau under indhold og mediearkiv. + Kun dokumenttyper med denne indstilling aktiveret kan oprettes i rodniveau under + indhold og mediearkiv. + Tilladte typer Tillad at oprette indhold af en specifik type under denne. Vælg child node - Nedarv faner og egenskaber fra en anden dokumenttype. Nye faner vil blive tilføjet den nuværende dokumenttype eller sammenflettet hvis fanenavnene er ens. - Indholdstypen bliver brugt i en komposition og kan derfor ikke blive anvendt som komposition + Nedarv faner og egenskaber fra en anden dokumenttype. Nye faner vil blive + tilføjet den nuværende dokumenttype eller sammenflettet hvis fanenavnene er ens. + + Indholdstypen bliver brugt i en komposition og kan derfor ikke blive anvendt som + komposition + Der er ingen indholdstyper tilgængelige at bruge som komposition - Når du fjerner en komposition vil alle associerede indholdsdata blive slettet. Når først dokumenttypen er gemt, er der ingen vej tilbage. + Når du fjerner en komposition vil alle associerede indholdsdata blive slettet. + Når først dokumenttypen er gemt, er der ingen vej tilbage. + Opret ny indstilling Genbrug Input indstillinger @@ -1420,21 +1596,30 @@ Mange hilsner fra Umbraco robotten Alle dokumenttyper Alle dokumenter Alle medier - som benytter denne dokumenttype vil blive slettet permanent. Bekræft at du også vil slette dem. - som benytter denne medietype vil blive slettet permanent. Bekræft at du også vil slette dem. - som benytter denne medlemstype vil blive slettet permanent. Bekræft at du også vil slette dem. + som benytter denne dokumenttype vil blive slettet permanent. Bekræft at du også vil + slette dem. + + som benytter denne medietype vil blive slettet permanent. Bekræft at du også vil slette + dem. + + som benytter denne medlemstype vil blive slettet permanent. Bekræft at du også vil + slette dem. + og alle dokumenter, som benytter denne type og alle medier, som benytter denne type og alle medlemmer, som benytter denne type Medlem kan redigere Tillad at denne egenskab kan redigeres af medlemmet på dets profil. Er følsom data - Skjul værdien af denne egenskab for indholdsredaktører der ikke har adgang til at se følsomme data + Skjul værdien af denne egenskab for indholdsredaktører der ikke har adgang + til at se følsomme data + Vis på medlemsprofil Tillad at denne egenskab kan vises på medlemmets profil. fane har ingen sorteringsrækkefølge Hvor er denne komposition brugt? - Denne komposition brugt i kompositionen af de følgende indholdstyper: + Denne komposition brugt i kompositionen af de følgende indholdstyper: + Tillad variationer Tillad sprogvariation Tillad segmentering @@ -1447,12 +1632,20 @@ Mange hilsner fra Umbraco robotten Tillad segmentering Element-type Er en Element-type - En Element-type er tiltænkt brug i f.eks. Nested Content, ikke i indholdstræet. - En Dokumenttype kan ikke ændres til en Element-type efter den er blevet brugt til at oprette en eller flere indholds elementer. + En Element-type er tiltænkt brug i f.eks. Nested Content, ikke i indholdstræet. + + En Dokumenttype kan ikke ændres til en Element-type efter den er blevet brugt til + at oprette en eller flere indholds elementer. + Dette benyttes ikke for en Element-type - Du har lavet ændringer til denne egenskab. Er du sikker på at du vil kassere dem? + Du har lavet ændringer til denne egenskab. Er du sikker på at du vil kassere dem? + Visning Label hen over (fuld bredde) + Du fjerner noden + Fjernelse af noden, begrænser redaktørens muligheder for at oprette forskellige + typer af underindhold. + Tilføj sprog @@ -1460,10 +1653,13 @@ Mange hilsner fra Umbraco robotten Egenskaber på dette sprog skal være udfyldt før noden kan blive udgivet. Standardsprog Et Umbraco-site kan kun have ét standardsprog. - At skifte standardsprog kan resultere i at standardindhold mangler. + At skifte standardsprog kan resultere i at standardindhold mangler. + Fallback til Intet fallback-sprog - For at tillade flersproget indhold, som ikke er tilgængeligt i det anmodede sprog, skal du her vælge et sprog at falde tilbage på. + For at tillade flersproget indhold, som ikke er tilgængeligt i det anmodede + sprog, skal du her vælge et sprog at falde tilbage på. + Fallback-sprog ingen @@ -1511,24 +1707,34 @@ Mange hilsner fra Umbraco robotten Standard felter Store bogstaver URL encode - Hvis indholdet af felterne skal sendes til en URL, skal denne slåes til så specialtegn formateres + Hvis indholdet af felterne skal sendes til en URL, skal denne slåes til så specialtegn + formateres + Denne tekst bruges hvis ovenstående felter er tomme Dette felt vil blive brugt hvis ovenstående felt er tomt - Ja, med klokkeslæt. Dato/tid separator: + Ja, med klokkeslæt. Dato/tid separator: Oversættelsesdetaljer Download XML DTD Felter Inkluder undersider - Hej %0%. Dette er en automatisk mail sendt for at informere dig om at dokumentet '%1' har en forespørgsel omkring oversættelse til '%5%' af %2%. Gå til http://%3%/translation/details.aspx?id=%4% for at redigere. Eller log ind i Umbraco for at få en oversigt over dine oversættelsesopgaver: http://%3%/Umbraco Hav en god dag! Mange hilsner Umbraco-robotten - Ingen oversættelsesbrugere er fundet. Opret venligst en oversættelsesbruger før du begynder at sende indhold til oversættelse + Hej %0%. Dette er en automatisk mail sendt for at informere dig om at dokumentet '%1' har en + forespørgsel omkring oversættelse til '%5%' af %2%. Gå til http://%3%/translation/details.aspx?id=%4% for at + redigere. Eller log ind i Umbraco for at få en oversigt over dine oversættelsesopgaver: http://%3%/Umbraco Hav en + god dag! Mange hilsner Umbraco-robotten + + Ingen oversættelsesbrugere er fundet. Opret venligst en oversættelsesbruger før du + begynder at sende indhold til oversættelse + Siden '%0%' er blevet sent til oversættelse Send siden '%0%' til oversættelse Totalt antal ord Oversæt til Oversættelse gennemført. - Du kan gennemse de sider, som du lige har oversat, ved at klikke nedenfor. Hvis den originale side bliver fundet, vil du blive præsenteret for en sammenligning af de to sider. + Du kan gennemse de sider, som du lige har oversat, ved at klikke nedenfor. Hvis den + originale side bliver fundet, vil du blive præsenteret for en sammenligning af de to sider. + Oversættelse fejlede, XML-filen kan være korrupt (indeholde fejl) Oversættelsesmuligheder Oversætter @@ -1596,10 +1802,14 @@ Mange hilsner fra Umbraco robotten er ikke blevet låst ude Kodeordet er ikke blevet ændret Gentag dit nye kodeord - Du kan ændre dit kodeord, som giver dig adgang til Umbraco backoffice ved at udfylde formularen og klikke på knappen 'Skift dit kodeord' + Du kan ændre dit kodeord, som giver dig adgang til Umbraco backoffice ved at + udfylde formularen og klikke på knappen 'Skift dit kodeord' + Indholdskanal Opret endnu en bruger - Opret nye brugere for at give dem adgang til Umbraco. Når en ny bruger oprettes, genereres der en adgangskode, som du kan dele med brugeren. + Opret nye brugere for at give dem adgang til Umbraco. Når en ny bruger oprettes, + genereres der en adgangskode, som du kan dele med brugeren. + Beskrivelsesfelt Deaktivér bruger Dokumenttype @@ -1609,7 +1819,9 @@ Mange hilsner fra Umbraco robotten Gå til brugerprofil Tilføj grupper for at tildele adgang og tilladelser Invitér anden bruger - Invitér nye brugere til at give dem adgang til Umbraco. En invitation vil blive sendt via e-mail til brugeren med oplysninger om, hvordan man logger ind i Umbraco. + Invitér nye brugere til at give dem adgang til Umbraco. En invitation vil blive sendt + via e-mail til brugeren med oplysninger om, hvordan man logger ind i Umbraco. + Sprog Indstil det sprog, du vil se i menuer og dialoger Senest låst ude @@ -1654,16 +1866,26 @@ Mange hilsner fra Umbraco robotten Begræns indholdstræet til bestemte startnoder Bruger sidst opdateret er blevet oprettet - Den nye bruger er blevet oprettet. For at logge ind i Umbraco skal du bruge adgangskoden nedenfor. + Den nye bruger er blevet oprettet. For at logge ind i Umbraco skal du bruge + adgangskoden nedenfor. + Brugeradministration Navn Brugertilladelser Brugergruppe er blevet inviteret - En invitation er blevet sendt til den nye bruger med oplysninger om, hvordan man logger ind i Umbraco. - Hej og velkommen til Umbraco! På bare 1 minut vil du være klar til at komme i gang, vi skal bare have dig til at oprette en adgangskode og tilføje et billede til din avatar. - Velkommen til Umbraco! Desværre er din invitation udløbet. Kontakt din administrator og bed om at gensende invitationen. - Hvis du uploader et billede af dig selv, gør du det nemt for andre brugere at genkende dig. Klik på cirklen ovenfor for at uploade et billede. + En invitation er blevet sendt til den nye bruger med oplysninger om, hvordan man + logger ind i Umbraco. + + Hej og velkommen til Umbraco! På bare 1 minut vil du være klar til at komme i + gang, vi skal bare have dig til at oprette en adgangskode og tilføje et billede til din avatar. + + Velkommen til Umbraco! Desværre er din invitation udløbet. Kontakt din + administrator og bed om at gensende invitationen. + + Hvis du uploader et billede af dig selv, gør du det nemt for andre brugere at + genkende dig. Klik på cirklen ovenfor for at uploade et billede. + Forfatter Skift Din profil @@ -1674,7 +1896,8 @@ Mange hilsner fra Umbraco robotten Send invitation Tilbage til brugere Umbraco: Invitation -

Hej %0%, du er blevet inviteret af %1% til Umbraco backoffice.

Besked fra %1%: %2%

Klik på dette link for acceptere invitationen

Hvis du ikke kan klikke på linket, så kopier og indsæt denne URL i dit browservindue

%3%

]]>
+ +

Hej %0%, du er blevet inviteret af %1% til Umbraco backoffice.

Besked fra %1%: %2%

Klik på dette link for acceptere invitationen

Hvis du ikke kan klikke på linket, så kopier og indsæt denne URL i dit browservindue

%3%

]]>
Gensender invitation... Slet bruger Er du sikker på du ønsker at slette denne brugers konto? @@ -1703,7 +1926,7 @@ Mange hilsner fra Umbraco robotten Indtast en selvvalgt validerings fejlbesked (valgfrit) Du skal tilføje mindst Du kan kun have - Tilføj op til + Tilføj op til elementer URL(er) URL(er) valgt @@ -1728,15 +1951,21 @@ Mange hilsner fra Umbraco robotten Viderestil URL håndtering De følgende URLs viderestiller til dette indholds element Der er ikke lavet nogen viderestillinger - Når en udgivet side bliver omdøbt eller flyttet, vil en viderestilling automatisk blive lavet til den nye side. + Når en udgivet side bliver omdøbt eller flyttet, vil en viderestilling + automatisk blive lavet til den nye side. + Viderestillings URL fjernet. Fejl under fjernelse af viderestillings URL. Dette vil fjerne viderestillingen Er du sikker på at du vil slå URL trackeren fra? URL tracker er nu slået fra. - Der opstod en fejl under forsøget på at slå URL trackeren fra, der findes mere information i logfilen. + Der opstod en fejl under forsøget på at slå URL trackeren fra, der findes mere information + i logfilen. + URL tracker er nu slået fra. - Der opstod en fejl under forsøget på at slå URL trackeren til, der findes mere information i logfilen. + Der opstod en fejl under forsøget på at slå URL trackeren til, der findes mere information + i logfilen. + Ingen ordbog elementer at vælge imellem @@ -1749,7 +1978,9 @@ Mange hilsner fra Umbraco robotten Slettet indhold med Id: {0} Relateret til original "parent" med id: {1} Slettet medie med Id: {0} relateret til original "parent" / mappe med id: {1} Kan ikke automatisk genoprette dette element - Der er ikke nogen placering hvor dette element automatisk kan genoprettes. Du kan flytte elementet manuelt i træet nedenfor. + Der er ikke nogen placering hvor dette element automatisk kan genoprettes. + Du kan flytte elementet manuelt i træet nedenfor. + blev genoprettet under @@ -1819,7 +2050,9 @@ Mange hilsner fra Umbraco robotten Vis flere muligheder Søg i Umbraco backoffice Søg efter indholdsnoder, medienoder osv. i backoffice - Når autoudfyldnings resultaterne er klar, tryk op og ned pilene, eller benyt tab knappen og brug enter knappen til at vælge. + Når autoudfyldnings resultaterne er klar, tryk op og ned pilene, eller benyt tab + knappen og brug enter knappen til at vælge. + Vej Fundet i Har oversættelse @@ -1861,7 +2094,9 @@ Mange hilsner fra Umbraco robotten Søg med Bing Søg efter denne besked på Bing Søg på Our Umbraco - Søg efter denne besked på Our Umbraco forum og dokumentation + Søg efter denne besked på Our Umbraco forum og + dokumentation + Søg på Our Umbraco med Google Søg på Our Umbraco forum med Google Søg i Umbraco kildekoden @@ -1914,14 +2149,20 @@ Mange hilsner fra Umbraco robotten Label Speciel visning Vis speciel visning beskrivelsen - Overskrift hvordan denne block præsenteres i backoffice interfacet. Vælg en .html fil der indeholder din præsensation. + Overskrift hvordan denne block præsenteres i backoffice interfacet. Vælg en + .html fil der indeholder din præsensation. + Indstillings model Rederings lagets størrelse Tilføj speciel visning Tilføj instillinger - %0%?]]> - %0%?]]> - Indholdet vil stadigt eksistere, men redigering af dette indhold vil ikke være muligt. Indholdet vil blive vist som ikke understøttet indhold. + + %0%?]]> + + %0%?]]> + Indholdet vil stadigt eksistere, men redigering af dette indhold vil ikke + være muligt. Indholdet vil blive vist som ikke understøttet indhold. + Billede Tilføj billede @@ -1941,10 +2182,12 @@ Mange hilsner fra Umbraco robotten Hvad er Indholdsskabeloner? - Indholdsskabeloner er foruddefineret indhold der kan vælges når der oprettes nye indholdselementer. + Indholdsskabeloner er foruddefineret indhold der kan vælges når der oprettes nye + indholdselementer. + Hvordan opretter jeg en Indholdsskabelon? - Der er to måder at oprette Indholdsskabeloner på:

  • Højreklik på en indholdsnode og vælg "Opret indholdsskabelon" for at oprette en ny Indholdsskabelon.
  • @@ -1952,9 +2195,12 @@ Mange hilsner fra Umbraco robotten

Når indholdsskabelonen har fået et navn, kan redaktører begynde at bruge indholdsskabelonen som udgangspunkt for deres nye side.

]]> -
+
Hvordan vedligeholder jeg Indholdsskabeloner? - Du kan redigere og slette Indholdsskabeloner fra "Indholdsskabeloner" i sektionen Indstillinger. Fold dokumenttypen som Indholdsskabelonen er baseret på ud og klik på den for at redigere eller slette den. + Du kan redigere og slette Indholdsskabeloner fra "Indholdsskabeloner" i sektionen + Indstillinger. Fold dokumenttypen som Indholdsskabelonen er baseret på ud og klik på den for at redigere eller + slette den. + Afslut @@ -1962,10 +2208,14 @@ Mange hilsner fra Umbraco robotten Vis i nyt vindue Åben forhåndsvisning i nyt vindue Forhåndsvisning af indholdet? - Du har afslutet forhåndsvisning, vil du starte forhåndsvisning igen for at se seneste gemte version af indholdet? + Du har afslutet forhåndsvisning, vil du starte forhåndsvisning igen for at + se seneste gemte version af indholdet? + Se udgivet indhold Se udgivet indhold? - Du er i forhåndsvisning, vil du afslutte for at se den udgivet version? + Du er i forhåndsvisning, vil du afslutte for at se den udgivet + version? + Se udgivet version Forbliv i forhåndsvisning diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/de.xml b/src/Umbraco.Web.UI/umbraco/config/lang/de.xml index 8b1496c3f3a6..8f2ba350d0a6 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/de.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/de.xml @@ -281,8 +281,8 @@ Neues Element anlegen Aus der Zwischenablage einfügen - - Erzeuge eine neue Inhaltsvorlage von '%0%' + + %0%]]> Leer Wählen Sie eine Inhaltsvorlage Inhaltsvorlage erzeugt diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 66436230e2eb..9d551919f910 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -101,7 +101,7 @@ Domain '%0%' has been updated Edit Current Domains - Inherit Culture @@ -160,7 +160,7 @@ Content deleted Content unpublished Content saved and Published - Content saved and published for languages: %0% + Content saved and published for languages: %0% Content saved Content saved for languages: %0% Content moved @@ -221,8 +221,12 @@ Page title This media item has no link Properties - This document is published but is not visible because the parent '%0%' is unpublished - This culture is published but is not visible because it is unpublished on parent '%0%' + This document is published but is not visible because the parent '%0%' is + unpublished + + This culture is published but is not visible because it is unpublished on + parent '%0%' + This document is published but is not in the cache Could not get the URL This document is published but its URL would collide with content %0% @@ -231,14 +235,18 @@ Published Published (pending changes) Publication Status - %0% and all content items underneath and thereby making their content publicly available.]]> - + + %0% and all content items underneath and thereby making their content publicly available.]]> + + Publish at Unpublish at Clear Date Set date Sortorder is updated - To sort the nodes, simply drag the nodes or click one of the column headers. You can select multiple nodes by holding the "shift" or "control" key while selecting + To sort the nodes, simply drag the nodes or click one of the column headers. You can select + multiple nodes by holding the "shift" or "control" key while selecting + Statistics Title (optional) Alternative text (optional) @@ -257,26 +265,37 @@ Child items Target This translates to the following time on the server: - What does this mean?]]> + + What does this mean?]]> Are you sure you want to delete this item? - Property %0% uses editor %1% which is not supported by Nested Content. + Property %0% uses editor %1% which is not supported by Nested + Content. + Are you sure you want to delete all items? No Content Types are configured for this property. Add Element Type Select Element Type - Select the group whose properties should be displayed. If left blank, the first group on the Element Type will be used. - Enter an angular expression to evaluate against each item for its name. Use + Select the group whose properties should be displayed. If left blank, the + first group on the Element Type will be used. + + Enter an angular expression to evaluate against each item for its + name. Use + to display the item index Add another text box Remove this text box Content root Include unpublished content items. - This value is hidden. If you need access to view this value please contact your website administrator. + This value is hidden. If you need access to view this value please contact your + website administrator. + This value is hidden. What languages would you like to publish? What languages would you like to send for approval? What languages would you like to schedule? - Select the languages to unpublish. Unpublishing a mandatory language will unpublish all languages. + Select the languages to unpublish. Unpublishing a mandatory language will + unpublish all languages. + All new variants will be saved. Which variants would you like to publish? Choose which variants to be saved. @@ -292,13 +311,15 @@ This item is in the Recycle Bin - Create a new Content Template from '%0%' + %0%]]> Blank Select a Content Template Content Template created A Content Template was created from '%0%' Another Content Template with the same name already exists - A Content Template is predefined content that an editor can select to use as the basis for creating new content + A Content Template is predefined content that an editor can select to use as the + basis for creating new content + Click to upload @@ -333,26 +354,44 @@ Select the Document Type you want to make a content template for Enter a folder name Choose a type and a title - Document Types within the Settings section, by editing the Allowed child node types under Permissions.]]> - Document Types within the Settings section.]]> - The selected page in the content tree doesn't allow for any pages to be created below it. + + Document Types within the Settings section, by editing the Allowed child node types under Permissions.]]> + + Document Types within the Settings section.]]> + The selected page in the content tree doesn't allow for any pages + to be created below it. + Edit permissions for this Document Type Create a new Document Type - Document Types within the Settings section, by changing the Allow as root option under Permissions.]]> - Media Types within the Settings section, by editing the Allowed child node types under Permissions.]]> - The selected media in the tree doesn't allow for any other media to be created below it. + + Document Types within the Settings section, by changing the Allow as root option under Permissions.]]> + + Media Types within the Settings section, by editing the Allowed child node types under Permissions.]]> + The selected media in the tree doesn't allow for any other media to be + created below it. + Edit permissions for this Media Types Document Type without a template Document Type with Template - The data definition for a content page that can be created by editors in the content tree and is directly accessible via a URL. + The data definition for a content page that can be created by + editors in the content tree and is directly accessible via a URL. + Document Type - The data definition for a content component that can be created by editors in the content tree and be picked on other pages but has no direct URL. + The data definition for a content component that can be created by editors in + the content tree and be picked on other pages but has no direct URL. + Element Type - Defines the schema for a repeating set of properties, for example, in a 'Block List' or 'Nested Content' property editor. + Defines the schema for a repeating set of properties, for example, in a 'Block + List' or 'Nested Content' property editor. + Composition - Defines a re-usable set of properties that can be included in the definition of multiple other Document Types. For example, a set of 'Common Page Settings'. + Defines a re-usable set of properties that can be included in the definition of + multiple other Document Types. For example, a set of 'Common Page Settings'. + Folder - Used to organise the Document Types, Compositions and Element Types created in this Document Type tree. + Used to organise the Document Types, Compositions and Element Types created in this + Document Type tree. + New folder New Data Type New JavaScript file @@ -377,11 +416,17 @@ Stay Discard changes You have unsaved changes - Are you sure you want to navigate away from this page? - you have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved + changes + Publishing will make the selected items visible on the site. - Unpublishing will remove the selected items and all their descendants from the site. + Unpublishing will remove the selected items and all their descendants from the + site. + Unpublishing will remove this page and all its descendants from the site. - You have unsaved changes. Making changes to the Document Type will discard the changes. + You have unsaved changes. Making changes to the Document Type will discard the + changes. + Done @@ -414,7 +459,6 @@ Manage hostnames Close this window Are you sure you want to delete - %0% of %1% items]]> Are you sure you want to disable Are you sure you want to remove %0%]]> @@ -432,7 +476,9 @@ Click to add a Macro Insert table This will delete the language - Changing the culture for a language may be an expensive operation and will result in the content cache and indexes being rebuilt + Changing the culture for a language may be an expensive operation and will result + in the content cache and indexes being rebuilt + Last Edited Link Internal link: @@ -444,16 +490,25 @@ Set permissions for Set permissions for %0% for user group %1% Select the users groups you want to set permissions for - The items in the recycle bin are now being deleted. Please do not close this window while this operation takes place + The items in the recycle bin are now being deleted. Please do not close this window + while this operation takes place + The recycle bin is now empty When items are deleted from the recycle bin, they will be gone forever - regexlib.com's webservice is currently experiencing some problems, which we have no control over. We are very sorry for this inconvenience.]]> - Search for a regular expression to add validation to a form field. Example: 'email, 'zip-code', 'URL'. + + regexlib.com's webservice is currently experiencing some problems, which we have no control over. We are very sorry for this inconvenience.]]> + Search for a regular expression to add validation to a form field. Example: 'email, + 'zip-code', 'URL'. + Remove Macro Required Field Site is reindexed - The website cache has been refreshed. All publish content is now up to date. While all unpublished content is still unpublished - The website cache will be refreshed. All published content will be updated, while unpublished content will stay unpublished. + The website cache has been refreshed. All publish content is now up to date. While all + unpublished content is still unpublished + + The website cache will be refreshed. All published content will be updated, while + unpublished content will stay unpublished. + Number of columns Number of rows Click on the image to see full size @@ -494,14 +549,15 @@ account Select editor Select snippet - This will delete the node and all its languages. If you only want to delete one language, you should unpublish the node in that language instead. + This will delete the node and all its languages. If you only want to delete one + language, you should unpublish the node in that language instead. + %0%.]]> %0% from the %1% group]]> Yes, remove There are no dictionary items. - Create dictionary item Configured Searchers - Shows properties and tools for any configured Searcher (i.e. such as a multi-index searcher) + Shows properties and tools for any configured Searcher (i.e. such as a + multi-index searcher) + Field values Health status The health status of the index and if it can be read @@ -523,7 +581,9 @@ Index info Lists the properties of the index Manage Examine's indexes - Allows you to view the details of each index and provides some tools for managing the indexes + Allows you to view the details of each index and provides some tools for + managing the indexes + Rebuild index @@ -537,7 +597,9 @@ Tools to manage the index fields The index cannot be read and will need to be rebuilt - The process is taking longer than expected, check the Umbraco log to see if there have been any errors during this operation + The process is taking longer than expected, check the Umbraco log to see if there + have been any errors during this operation + This index cannot be rebuilt because it has no assigned IIndexPopulator @@ -591,12 +653,18 @@ was moved underneath - Your data has been saved, but before you can publish this page there are some errors you need to fix first: - The current membership provider does not support changing password (EnablePasswordRetrieval need to be true) + Your data has been saved, but before you can publish this page there are some + errors you need to fix first: + + The current membership provider does not support changing password + (EnablePasswordRetrieval need to be true) + %0% already exists There were errors: There were errors: - The password should be a minimum of %0% characters long and contain at least %1% non-alpha numeric character(s) + The password should be a minimum of %0% characters long and contain at least %1% + non-alpha numeric character(s) + %0% must be an integer The %0% field in the %1% tab is mandatory %0% is a mandatory field @@ -606,13 +674,17 @@ Received an error from the server The specified file type has been disallowed by the administrator - NOTE! Even though CodeMirror is enabled by configuration, it is disabled in Internet Explorer because it's not stable enough. + NOTE! Even though CodeMirror is enabled by configuration, it is disabled in + Internet Explorer because it's not stable enough. + Please fill both alias and name on the new property type! There is a problem with read/write access to a specific file or folder Error loading Partial View script (file: %0%) Please enter a title Please choose a type - You're about to make the picture larger than the original size. Are you sure that you want to proceed? + You're about to make the picture larger than the original size. Are you sure + that you want to proceed? + Startnode deleted, please contact your administrator Please mark content before changing style No active styles available @@ -774,6 +846,8 @@ Articles Videos Avatar for + Header + system field Blue @@ -813,21 +887,24 @@ The installer cannot connect to the database. - the documentation). Please modify the connection string manually.]]> + Could not save the web.config file. Please modify the connection string + manually. + Your database has been found and is identified as Database configuration - - + install button to install the Umbraco %0% database ]]> - - Next to proceed.]]> - Database not found! Please check that the information in the "ConnectionStrings" property in your configuration source is correct, for example, in appsettings.json (see the documentation).

-

To proceed, please edit your configuration source, for example, appsettings.json (see the documentation), add the connection string for your database in the key named "umbracoDbDSN".

+
+ + Next to proceed.]]> + Database not found! Please check that the information in the "connection string" of the "web.config" file is correct.

+

To proceed, please edit the "web.config" file (using Visual Studio or your favourite text editor), scroll to the bottom, add the connection string for your database in the key named "UmbracoDbDSN" and save the file.

Click the retry button when - done.
- More information on editing your configurations here (choose "Connection string settings").

]]>
+ done.
+ More information on editing web.config here.

]]>
Please contact your ISP if necessary. If you're installing on a local machine or server you might need information from your system administrator.]]> @@ -840,22 +917,33 @@ ]]>
Press Next to proceed. ]]> - next to continue the configuration wizard]]> - The Default users' password needs to be changed!]]> - The Default user has been disabled or has no access to Umbraco!

No further actions needs to be taken. Click Next to proceed.]]> - The Default user's password has been successfully changed since the installation!

No further actions needs to be taken. Click Next to proceed.]]> + + next to continue the configuration wizard]]> + + The Default users' password needs to be changed!]]> + + The Default user has been disabled or has no access to Umbraco!

No further actions needs to be taken. Click Next to proceed.]]> + + The Default user's password has been successfully changed since the installation!

No further actions needs to be taken. Click Next to proceed.]]> The password is changed! Get a great start, watch our introduction videos - By clicking the next button, you accept the license for this software as specified in the box below. Notice that this Umbraco distribution consists of two different licenses, the open source MIT license for the framework and the Umbraco freeware license that covers the UI. + By clicking the next button (or modifying the umbracoConfigurationStatus in web.config), + you accept the license for this software as specified in the box below. Notice that this Umbraco distribution + consists of two different licenses, the open source MIT license for the framework and the Umbraco freeware license + that covers the UI. + Not installed yet. Affected files and folders More information on setting up permissions for Umbraco here - You need to grant ASP.NET modify permissions to the following files/folders + You need to grant ASP.NET modify permissions to the following + files/folders + Your permission settings are almost perfect!

You can run Umbraco without problems, but you will not be able to install packages which are recommended to take full advantage of Umbraco.]]>
How to Resolve Click here to read the text version - video tutorial on setting up folder permissions for Umbraco or read the text version.]]> + + video tutorial on setting up folder permissions for Umbraco or read the text version.]]> Your permission settings might be an issue!

You can run Umbraco without problems, but you will not be able to create folders or install packages which are recommended to take full advantage of Umbraco.]]>
@@ -865,7 +953,9 @@ Your permission settings are perfect!

You are ready to run Umbraco and install packages!]]>
Resolving folder issue - Follow this link for more information on problems with ASP.NET and creating folders + Follow this link for more information on problems with ASP.NET and + creating folders + Setting up folder permissions Further help and information Get help from our award winning community, browse the documentation or watch some free videos on how to build a simple site, how to use packages and a quick guide to the Umbraco terminology]]> Umbraco %0% is installed and ready for use - - + /web.config file and update the AppSetting key UmbracoConfigurationStatus in the bottom to the value of '%0%'.]]> started instantly by clicking the "Launch Umbraco" button below.
If you are new to Umbraco, you can find plenty of resources on our getting started pages.]]>
Launch Umbraco @@ -933,7 +1023,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Happy super Sunday - Happy manic Monday + Happy manic Monday Happy tubular Tuesday Happy wonderful Wednesday Happy thunderous Thursday @@ -942,10 +1032,15 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Log in below Sign in with Session timed out - © 2001 - %0%
Umbraco.com

]]>
+ + © 2001 - %0%
Umbraco.com

]]>
Forgotten password? - An email will be sent to the address specified with a link to reset your password - An email with password reset instructions will be sent to the specified address if it matched our records + An email will be sent to the address specified with a link to reset your + password + + An email with password reset instructions will be sent to the + specified address if it matched our records + Show password Hide password Return to login form @@ -1053,7 +1148,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont The current node is not allowed under the chosen node because of its type The current node cannot be moved to one of its subpages The current node cannot exist at the root - The action isn't allowed since you have insufficient permissions on 1 or more child documents. + The action isn't allowed since you have insufficient permissions on 1 or more child + documents. + Relate copied items to original @@ -1173,13 +1270,15 @@ To manage your website, simply open the Umbraco backoffice and start adding cont This package has no configuration view No packages have been created yet You don’t have any packages installed - 'Packages' icon in the top right of your screen]]> + + 'Packages' icon in the top right of your screen]]> Package Content License Search for packages Results for We couldn’t find anything for - Please try searching for another package or browse through the categories + Please try searching for another package or browse through the categories + Popular New releases has @@ -1193,7 +1292,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Downloads Likes Compatibility - This package is compatible with the following versions of Umbraco, as reported by community members. Full compatability cannot be guaranteed for versions reported below 100% + This package is compatible with the following versions of Umbraco, as + reported by community members. Full compatability cannot be guaranteed for versions reported below 100% + External sources Author Documentation @@ -1218,7 +1319,10 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Paste with full formatting (Not recommended) - The text you're trying to paste contains special characters or formatting. This could be caused by copying text from Microsoft Word. Umbraco can remove special characters or formatting automatically, so the pasted content will be more suitable for the web. + The text you're trying to paste contains special characters or formatting. This could be + caused by copying text from Microsoft Word. Umbraco can remove special characters or formatting automatically, so + the pasted content will be more suitable for the web. + Paste as raw text without any formatting at all Paste, but remove formatting (Recommended) @@ -1234,7 +1338,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Login Page Choose the page that contains the login form Remove protection... - %0%?]]> + + %0%?]]> Select the pages that contain login form and error messages %0%]]> %0%]]> @@ -1257,7 +1362,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont - + + Include unpublished subpages Publishing in progress - please wait... %0% out of %1% pages have been published... @@ -1286,7 +1392,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Edit %0% on %1% Discard creation? - You have made changes to this content. Are you sure you want to discard them? + You have made changes to this content. Are you sure you want to + discard them? + Remove all medias? Clipboard Not allowed @@ -1310,10 +1418,13 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Changes Created Current version - Red text will not be shown in the selected version. , green means added]]> + + Red text will not be shown in the selected version. , green means added]]> Document has been rolled back Select a version to compare with the current version - This displays the selected version as HTML, if you wish to see the difference between 2 versions at the same time, use the diff view + This displays the selected version as HTML, if you wish to see the difference between 2 + versions at the same time, use the diff view + Rollback to Select version View @@ -1346,7 +1457,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Default template - To import a Document Type, find the ".udt" file on your computer by clicking the "Browse" button and click "Import" (you'll be asked for confirmation on the next screen) + To import a Document Type, find the ".udt" file on your computer by clicking the + "Browse" button and click "Import" (you'll be asked for confirmation on the next screen) + New Tab Title Node type Type @@ -1357,7 +1470,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Tabs Master Content Type enabled This Content Type uses - No properties defined on this tab. Click on the "add a new property" link at the top to create a new property. + No properties defined on this tab. Click on the "add a new property" link at + the top to create a new property. + Create matching template Add icon @@ -1365,7 +1480,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Sort order Creation date Sorting complete. - Drag the different items up or down below to set how they should be arranged. Or click the column headers to sort the entire collection of items + Drag the different items up or down below to set how they should be arranged. Or click the + column headers to sort the entire collection of items + @@ -1417,6 +1534,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Media Type saved Member Type saved Member Group saved + Another Member Group with the same name already exists Template not saved Please make sure that you do not have 2 templates with the same alias Template saved @@ -1443,14 +1561,20 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Invitation has been re-sent to %0% Document Type was exported to file An error occurred while exporting the Document Type - Domains are not configured for multilingual site, please contact an administrator, see log for more information - There is no domain configured for %0%, please contact an administrator, see log for more information + Domains are not configured for multilingual site, please contact an administrator, + see log for more information + + There is no domain configured for %0%, please contact an administrator, see + log for more information + Add style Edit style Rich text editor styles - Define the styles that should be available in the rich text editor for this stylesheet + Define the styles that should be available in the rich text editor for this + stylesheet + Edit stylesheet Edit stylesheet property The name displayed in the editor style selector @@ -1472,20 +1596,24 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Insert Choose what to insert into your template Dictionary item - A dictionary item is a placeholder for a translatable piece of text, which makes it easy to create designs for multilingual websites. + A dictionary item is a placeholder for a translatable piece of text, which + makes it easy to create designs for multilingual websites. + Macro - A Macro is a configurable component which is great for - reusable parts of your design, where you need the option to provide parameters, - such as galleries, forms and lists. - + A Macro is a configurable component which is great for + reusable parts of your design, where you need the option to provide parameters, + such as galleries, forms and lists. + Value - Displays the value of a named field from the current page, with options to modify the value or fallback to alternative values. + Displays the value of a named field from the current page, with options to modify + the value or fallback to alternative values. + Partial view - A partial view is a separate template file which can be rendered inside another - template, it's great for reusing markup or for separating complex templates into separate files. - + A partial view is a separate template file which can be rendered inside another + template, it's great for reusing markup or for separating complex templates into separate files. + Master template No master Render child template @@ -1557,7 +1685,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Click to insert macro Write here... Grid Layouts - Layouts are the overall work area for the grid editor, usually you only need one or two different layouts + Layouts are the overall work area for the grid editor, usually you only need one or + two different layouts + Add Grid Layout Edit Grid Layout Adjust the layout by setting column widths and adding additional sections @@ -1583,8 +1713,13 @@ To manage your website, simply open the Umbraco backoffice and start adding cont are added You are deleting the row configuration - Deleting a row configuration name will result in loss of data for any existing content that is based on this configuration. - + Deleting a row configuration name will result in loss of data for any existing content that is based on this + configuration. + + You are deleting the layout + Modifying a layout will result in loss of data for any existing content that is based + on this configuration. + Compositions @@ -1595,18 +1730,29 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Add property Required label Enable list view - Configures the content item to show a sortable and searchable list of its children, the children will not be shown in the tree + Configures the content item to show a sortable and searchable list of its + children, the children will not be shown in the tree + Allowed Templates - Choose which templates editors are allowed to use on content of this type + Choose which templates editors are allowed to use on content of this type + Allow as root - Allow editors to create content of this type in the root of the content tree. + Allow editors to create content of this type in the root of the content tree. + Allowed child node types - Allow content of the specified types to be created underneath content of this type. + Allow content of the specified types to be created underneath content of this + type. + Choose child node - Inherit tabs and properties from an existing Document Type. New tabs will be added to the current Document Type or merged if a tab with an identical name exists. - This Content Type is used in a composition, and therefore cannot be composed itself. + Inherit tabs and properties from an existing Document Type. New tabs will be + added to the current Document Type or merged if a tab with an identical name exists. + + This Content Type is used in a composition, and therefore cannot be composed itself. + There are no Content Types available to use as a composition. - Removing a composition will delete all the associated property data. Once you save the Document Type there's no way back. + Removing a composition will delete all the associated property data. Once you + save the Document Type there's no way back. + Create new Use existing Editor settings @@ -1620,21 +1766,33 @@ To manage your website, simply open the Umbraco backoffice and start adding cont All Document Types All Documents All media items - using this Document Type will be deleted permanently, please confirm you want to delete these as well. - using this Media Type will be deleted permanently, please confirm you want to delete these as well. - using this Member Type will be deleted permanently, please confirm you want to delete these as well + using this Document Type will be deleted permanently, please confirm you want to + delete these as well. + + using this Media Type will be deleted permanently, please confirm you want to delete + these as well. + + using this Member Type will be deleted permanently, please confirm you want to delete + these as well + and all documents using this type and all media items using this type and all members using this type Member can edit - Allow this property value to be edited by the member on their profile page + Allow this property value to be edited by the member on their profile page + Is sensitive data - Hide this property value from content editors that don't have access to view sensitive information + Hide this property value from content editors that don't have access to view + sensitive information + Show on member profile - Allow this property value to be displayed on the member profile page + Allow this property value to be displayed on the member profile page + tab has no sort order Where is this composition used? - This composition is currently used in the composition of the following content types: + This composition is currently used in the composition of the following + content types: + Allow variations Allow vary by culture Allow segmentation @@ -1647,23 +1805,35 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Allow segmentation Element Type Is an Element Type - An Element Type is meant to be used for instance in Nested Content, and not in the tree. - A document Type cannot be changed to an Element Type once it has been used to create one or more content items. + An Element Type is meant to be used for instance in Nested Content, and not in the + tree. + + A document Type cannot be changed to an Element Type once it has been used to + create one or more content items. + This is not applicable for an Element Type You have made changes to this property. Are you sure you want to discard them? Appearance Label above (full-width) + You are removing the child node + Removing a child node will limit the editors options to create different content + types beneath a node. + Add language Mandatory language - Properties on this language have to be filled out before the node can be published. + Properties on this language have to be filled out before the node can be + published. + Default language An Umbraco site can only have one default language set. Switching default language may result in default content missing. Falls back to No fall back language - To allow multi-lingual content to fall back to another language if not present in the requested language, select it here. + To allow multi-lingual content to fall back to another language if not + present in the requested language, select it here. + Fall back language none @@ -1734,13 +1904,17 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Cheers from the Umbraco robot ]]> - No translator users found. Please create a translator user before you start sending content to translation + No translator users found. Please create a translator user before you start sending + content to translation + The page '%0%' has been send to translation Send the page '%0%' to translation Total words Translate to Translation completed. - You can preview the pages, you've just translated, by clicking below. If the original page is found, you will get a comparison of the 2 pages. + You can preview the pages, you've just translated, by clicking below. If the + original page is found, you will get a comparison of the 2 pages. + Translation failed, the XML file might be corrupt Translation options Translator @@ -1793,7 +1967,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Access - Based on the assigned groups and start nodes, the user has access to the following nodes + Based on the assigned groups and start nodes, the user has access to the following nodes + Assign access Administrator Category field @@ -1806,10 +1981,14 @@ To manage your website, simply open the Umbraco backoffice and start adding cont hasn't been locked out The password hasn't been changed Confirm new password - You can change your password for accessing the Umbraco backoffice by filling out the form below and click the 'Change Password' button + You can change your password for accessing the Umbraco backoffice by filling + out the form below and click the 'Change Password' button + Content Channel Create another user - Create new users to give them access to Umbraco. When a new user is created a password will be generated that you can share with the user. + Create new users to give them access to Umbraco. When a new user is created a password + will be generated that you can share with the user. + Description field Disable User Document Type @@ -1819,7 +1998,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Go to user profile Add groups to assign access and permissions Invite another user - Invite new users to give them access to Umbraco. An invite email will be sent to the user with information on how to log in to Umbraco. Invites last for 72 hours. + Invite new users to give them access to Umbraco. An invite email will be sent to the + user with information on how to log in to Umbraco. Invites last for 72 hours. + Language Set the language you will see in menus and dialogs Last lockout date @@ -1843,7 +2024,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Your new password cannot be blank! Current password Invalid current password - There was a difference between the new password and the confirmed password. Please try again! + There was a difference between the new password and the confirmed password. Please + try again! + The confirmed password doesn't match the new password! Replace child node permissions You are currently modifying permissions for the pages: @@ -1864,16 +2047,26 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Limit the content tree to specific start nodes User last updated has been created - The new user has successfully been created. To log in to Umbraco use the password below. + The new user has successfully been created. To log in to Umbraco use the + password below. + User management Name User permissions User group has been invited - An invitation has been sent to the new user with details about how to log in to Umbraco. - Hello there and welcome to Umbraco! In just 1 minute you’ll be good to go, we just need you to setup a password and add a picture for your avatar. - Welcome to Umbraco! Unfortunately your invite has expired. Please contact your administrator and ask them to resend it. - Uploading a photo of yourself will make it easy for other users to recognize you. Click the circle above to upload your photo. + An invitation has been sent to the new user with details about how to log in to + Umbraco. + + Hello there and welcome to Umbraco! In just 1 minute you’ll be good to go, we + just need you to setup a password and add a picture for your avatar. + + Welcome to Umbraco! Unfortunately your invite has expired. Please contact your + administrator and ask them to resend it. + + Uploading a photo of yourself will make it easy for other users to recognize + you. Click the circle above to upload your photo. + Writer Change Your profile @@ -2028,14 +2221,19 @@ To manage your website, simply open the Umbraco backoffice and start adding cont 3: Configuration file path --> Value is set to the recommended value: '%0%'. - Expected value '%1%' for '%2%' in configuration file '%3%', but found '%0%'. - Found unexpected value '%0%' for '%2%' in configuration file '%3%'. + Expected value '%1%' for '%2%' in configuration file '%3%', but + found '%0%'. + + Found unexpected value '%0%' for '%2%' in configuration file '%3%'. + MacroErrors are set to '%0%'. - MacroErrors are set to '%0%' which will prevent some or all pages in your site from loading completely if there are any errors in macros. Rectifying this will set the value to '%1%'. + MacroErrors are set to '%0%' which will prevent some or all pages in + your site from loading completely if there are any errors in macros. Rectifying this will set the value to '%1%'. + Debug compilation mode is disabled. - Debug compilation mode is currently enabled. It is recommended to disable this setting before go live. + Debug compilation mode is currently enabled. It is recommended to + disable this setting before go live. + @@ -2062,30 +2266,48 @@ To manage your website, simply open the Umbraco backoffice and start adding cont - X-Frame-Options used to control whether a site can be IFRAMEd by another was found.]]> - X-Frame-Options used to control whether a site can be IFRAMEd by another was not found.]]> - X-Content-Type-Options used to protect against MIME sniffing vulnerabilities was found.]]> - X-Content-Type-Options used to protect against MIME sniffing vulnerabilities was not found.]]> - Strict-Transport-Security, also known as the HSTS-header, was found.]]> - Strict-Transport-Security was not found.]]> + + X-Frame-Options used to control whether a site can be IFRAMEd by another was found.]]> + + X-Frame-Options used to control whether a site can be IFRAMEd by another was not found.]]> + + X-Content-Type-Options used to protect against MIME sniffing vulnerabilities was found.]]> + + X-Content-Type-Options used to protect against MIME sniffing vulnerabilities was not found.]]> + + Strict-Transport-Security, also known as the HSTS-header, was found.]]> + + Strict-Transport-Security was not found.]]> X-XSS-Protection was found.]]> - X-XSS-Protection was not found.]]> + + X-XSS-Protection was not found.]]> - %0%.]]> - No headers revealing information about the website technology were found. - the documentation), Umbraco:CMS:Global:Smtp could not be found.]]> - the documentation) Umbraco:CMS:Global:Smtp section, the host is not configured.]]> - SMTP settings are configured correctly and the service is operating as expected. - the documentation) is correct in the Umbraco:CMS:Global:Smtp section.]]> - %0%.]]> - %0%.]]> -

Results of the scheduled Umbraco Health Checks run on %0% at %1% are as follows:

%2%]]>
+ + %0%.]]> + No headers revealing information about the website technology were found. + + In the Web.config file, system.net/mailsettings could not be found. + In the Web.config file system.net/mailsettings section, the host is + not configured. + + SMTP settings are configured correctly and the service is operating + as expected. + + The SMTP server configured with host '%0%' and port '%1%' could not be + reached. Please check to ensure the SMTP settings in the Web.config file system.net/mailsettings are correct. + + + %0%.]]> + + %0%.]]> + +

Results of the scheduled Umbraco Health Checks run on %0% at %1% are as follows:

%2%]]>
Umbraco Health Check Status: %0% Check group - The health checker evaluates various areas of your site for best practice settings, configuration, potential problems, etc. You can easily fix problems by pressing a button. You can add your own health checks, have a look at the documentation for more information about custom health checks.

]]> @@ -2099,7 +2321,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Redirect URL Management The following URLs redirect to this content item: No redirects have been made - When a published page gets renamed or moved a redirect will automatically be made to the new page. + When a published page gets renamed or moved a redirect will automatically be + made to the new page. + Redirect URL removed. Error removing redirect URL. This will remove the redirect @@ -2120,7 +2344,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Trashed content with Id: {0} related to original parent content with Id: {1} Trashed media with Id: {0} related to original parent media item with Id: {1} Cannot automatically restore this item - There is no location where this item can be automatically restored. You can move the item manually using the tree below. + There is no location where this item can be automatically restored. You + can move the item manually using the tree below. + was restored under @@ -2190,8 +2416,10 @@ To manage your website, simply open the Umbraco backoffice and start adding cont View more options Search the Umbraco backoffice Search for content nodes, media nodes etc. across the backoffice. - When autocomplete results are available, press up and down arrows, or use the tab key and use the enter key to select. - Path: + When autocomplete results are available, press up and down arrows, or use the + tab key and use the enter key to select. + + Path: Found in Has translation Missing translation @@ -2216,8 +2444,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Delete Saved Search Log Levels - Select all - Deselect all + Select all + Deselect all Saved Searches Save Search Enter a friendly name for your search query @@ -2270,11 +2498,10 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Close Property Actions - Wait Refresh status Memory Cache - Reload Database Cache - Rebuilding can be expensive. Use it when reloading is not enough, and you think that the database cache has not been @@ -2295,7 +2522,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Rebuild Internals - not need to use it. ]]> @@ -2307,7 +2534,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Performance profiling - Umbraco currently runs in debug mode. This means you can use the built-in performance profiler to assess the performance when rendering pages.

@@ -2324,14 +2551,14 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Activate the profiler by default Friendly reminder - You should never let a production site run in debug mode. Debug mode is turned off by setting Umbraco:CMS:Hosting:Debug to false in appsettings.json, appsettings.{Environment}.json or via an environment variable.

]]>
- Umbraco currently does not run in debug mode, so you can't use the built-in profiler. This is how it should be for a production site.

@@ -2344,7 +2571,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Hours of Umbraco training videos are only a click away - Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit umbraco.tv for even more Umbraco videos

]]>
@@ -2352,41 +2579,48 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Start here - This section contains the building blocks for your Umbraco site. Follow the below links to find out more about working with the items in the Settings section + This section contains the building blocks for your Umbraco site. Follow the below + links to find out more about working with the items in the Settings section + Find out more - in the Documentation section of Our Umbraco ]]> - Community Forum ]]> - tutorial videos (some are free, some require a subscription) ]]> - productivity boosting tools and commercial support ]]> - training and certification opportunities ]]> Welcome to The Friendly CMS - Thank you for choosing Umbraco - we think this could be the beginning of something beautiful. While it may feel overwhelming at first, we've done a lot to make the learning curve as smooth and fast as possible. + Thank you for choosing Umbraco - we think this could be the beginning of something + beautiful. While it may feel overwhelming at first, we've done a lot to make the learning curve as smooth and fast + as possible. + Umbraco Forms - Create forms using an intuitive drag and drop interface. From simple contact forms that sends e-mails to advanced questionaires that integrate with CRM systems. Your clients will love it! + Create forms using an intuitive drag and drop interface. From simple contact forms + that sends e-mails to advanced questionaires that integrate with CRM systems. Your clients will love it! + Pick Element Type @@ -2406,14 +2640,20 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Label Custom view Show custom view description - Overwrite how this block appears in the backoffice UI. Pick a .html file containing your presentation. + Overwrite how this block appears in the backoffice UI. Pick a .html file + containing your presentation. + Settings model Overlay editor size Add custom view Add settings - %0%?]]> - %0%?]]> - The content of this block will still be present, editing of this content will no longer be available and will be shown as unsupported content. + + %0%?]]> + + %0%?]]> + The content of this block will still be present, editing of this content + will no longer be available and will be shown as unsupported content. + Thumbnail Add thumbnail @@ -2433,10 +2673,12 @@ To manage your website, simply open the Umbraco backoffice and start adding cont What are Content Templates? - Content Templates are pre-defined content that can be selected when creating a new content node. + Content Templates are pre-defined content that can be selected when creating a new + content node. + How do I create a Content Template? - There are two ways to create a Content Template:

  • Right-click a content node and select "Create Content Template" to create a new Content Template.
  • @@ -2446,7 +2688,10 @@ To manage your website, simply open the Umbraco backoffice and start adding cont ]]> How do I manage Content Templates? - You can edit and delete Content Templates from the "Content Templates" tree in the Settings section. Expand the Document Type which the Content Template is based on and click it to edit or delete it. + You can edit and delete Content Templates from the "Content Templates" tree in the + Settings section. Expand the Document Type which the Content Template is based on and click it to edit or delete + it. + End @@ -2454,11 +2699,15 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Preview website Open website in preview mode Preview website? - You have ended preview mode, do you want to enable it again to view the latest saved version of your website? + You have ended preview mode, do you want to enable it again to view the + latest saved version of your website? + Preview latest version View published version View published version? - You are in Preview Mode, do you want exit in order to view the published version of your website? + You are in Preview Mode, do you want exit in order to view the + published version of your website? + View published version Stay in preview mode diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml index 42e4dae49d78..6106bf04a99b 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -102,7 +102,7 @@ Domain '%0%' has been updated Edit Current Domains - Inherit Culture @@ -159,9 +159,9 @@ Viewing for Content deleted Content unpublished - Content unpublished for languages: %0% + Content unpublished for languages: %0% Content published - Content published for languages: %0% + Content published for languages: %0% Content saved Content saved for languages: %0% Content moved @@ -224,8 +224,12 @@ This media item has no link No content can be added for this item Properties - This document is published but is not visible because the parent '%0%' is unpublished - This culture is published but is not visible because it is unpublished on parent '%0%' + This document is published but is not visible because the parent '%0%' is + unpublished + + This culture is published but is not visible because it is unpublished on + parent '%0%' + This document is published but is not in the cache Could not get the URL This document is published but its URL would collide with content %0% @@ -234,14 +238,18 @@ Published Published (pending changes) Publication Status - %0% and all content items underneath and thereby making their content publicly available.]]> - + + %0% and all content items underneath and thereby making their content publicly available.]]> + + Publish at Unpublish at Clear Date Set date Sortorder is updated - To sort the nodes, simply drag the nodes or click one of the column headers. You can select multiple nodes by holding the "shift" or "control" key while selecting + To sort the nodes, simply drag the nodes or click one of the column headers. You can select + multiple nodes by holding the "shift" or "control" key while selecting + Statistics Title (optional) Alternative text (optional) @@ -261,26 +269,37 @@ Child items Target This translates to the following time on the server: - What does this mean?]]> + + What does this mean?]]> Are you sure you want to delete this item? Are you sure you want to delete all items? - Property %0% uses editor %1% which is not supported by Nested Content. + Property %0% uses editor %1% which is not supported by Nested + Content. + No Content Types are configured for this property. Add Element Type Select Element Type - Select the group whose properties should be displayed. If left blank, the first group on the Element Type will be used. - Enter an angular expression to evaluate against each item for its name. Use + Select the group whose properties should be displayed. If left blank, the + first group on the Element Type will be used. + + Enter an angular expression to evaluate against each item for its + name. Use + to display the item index Add another text box Remove this text box Content root Include unpublished content items. - This value is hidden. If you need access to view this value please contact your website administrator. + This value is hidden. If you need access to view this value please contact your + website administrator. + This value is hidden. What languages would you like to publish? What languages would you like to send for approval? What languages would you like to schedule? - Select the languages to unpublish. Unpublishing a mandatory language will unpublish all languages. + Select the languages to unpublish. Unpublishing a mandatory language will + unpublish all languages. + All new variants will be saved. Which variants would you like to publish? Choose which variants to be saved. @@ -296,13 +315,15 @@ This item is in the Recycle Bin - Create a new Content Template from '%0%' + %0%]]> Blank Select a Content Template Content Template created A Content Template was created from '%0%' Another Content Template with the same name already exists - A Content Template is predefined content that an editor can select to use as the basis for creating new content + A Content Template is predefined content that an editor can select to use as the + basis for creating new content + Click to upload @@ -344,26 +365,44 @@ Select the Document Type you want to make a content template for Enter a folder name Choose a type and a title - Document Types within the Settings section, by editing the Allowed child node types under Permissions.]]> - Document Types within the Settings section.]]> - The selected page in the content tree doesn't allow for any pages to be created below it. + + Document Types within the Settings section, by editing the Allowed child node types under Permissions.]]> + + Document Types within the Settings section.]]> + The selected page in the content tree doesn't allow for any pages + to be created below it. + Edit permissions for this Document Type Create a new Document Type - Document Types within the Settings section, by changing the Allow as root option under Permissions.]]> - Media Types Types within the Settings section, by editing the Allowed child node types under Permissions.]]> - The selected media in the tree doesn't allow for any other media to be created below it. + + Document Types within the Settings section, by changing the Allow as root option under Permissions.]]> + + Media Types Types within the Settings section, by editing the Allowed child node types under Permissions.]]> + The selected media in the tree doesn't allow for any other media to be + created below it. + Edit permissions for this Media Type Document Type without a template Document Type with Template - The data definition for a content page that can be created by editors in the content tree and is directly accessible via a URL. + The data definition for a content page that can be created by + editors in the content tree and is directly accessible via a URL. + Document Type - The data definition for a content component that can be created by editors in the content tree and be picked on other pages but has no direct URL. + The data definition for a content component that can be created by editors in + the content tree and be picked on other pages but has no direct URL. + Element Type - Defines the schema for a repeating set of properties, for example, in a 'Block List' or 'Nested Content' property editor. + Defines the schema for a repeating set of properties, for example, in a 'Block + List' or 'Nested Content' property editor. + Composition - Defines a re-usable set of properties that can be included in the definition of multiple other Document Types. For example, a set of 'Common Page Settings'. + Defines a re-usable set of properties that can be included in the definition of + multiple other Document Types. For example, a set of 'Common Page Settings'. + Folder - Used to organise the Document Types, Compositions and Element Types created in this Document Type tree. + Used to organise the Document Types, Compositions and Element Types created in this + Document Type tree. + New folder New Data Type New JavaScript file @@ -388,11 +427,17 @@ Stay Discard changes You have unsaved changes - Are you sure you want to navigate away from this page? - you have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved + changes + Publishing will make the selected items visible on the site. - Unpublishing will remove the selected items and all their descendants from the site. + Unpublishing will remove the selected items and all their descendants from the + site. + Unpublishing will remove this page and all its descendants from the site. - You have unsaved changes. Making changes to the Document Type will discard the changes. + You have unsaved changes. Making changes to the Document Type will discard the + changes. + Done @@ -424,7 +469,6 @@ Name Close this window Are you sure you want to delete - %0% of %1% items]]> Are you sure you want to disable Are you sure you want to remove %0%]]> @@ -442,7 +486,9 @@ Click to add a Macro Insert table This will delete the language - Changing the culture for a language may be an expensive operation and will result in the content cache and indexes being rebuilt + Changing the culture for a language may be an expensive operation and will result + in the content cache and indexes being rebuilt + Last Edited Link Internal link: @@ -454,16 +500,25 @@ Set permissions for Set permissions for %0% for user group %1% Select the users groups you want to set permissions for - The items in the recycle bin are now being deleted. Please do not close this window while this operation takes place + The items in the recycle bin are now being deleted. Please do not close this window + while this operation takes place + The recycle bin is now empty When items are deleted from the recycle bin, they will be gone forever - regexlib.com's webservice is currently experiencing some problems, which we have no control over. We are very sorry for this inconvenience.]]> - Search for a regular expression to add validation to a form field. Example: 'email, 'zip-code', 'URL'. + + regexlib.com's webservice is currently experiencing some problems, which we have no control over. We are very sorry for this inconvenience.]]> + Search for a regular expression to add validation to a form field. Example: 'email, + 'zip-code', 'URL'. + Remove Macro Required Field Site is reindexed - The website cache has been refreshed. All publish content is now up to date. While all unpublished content is still unpublished - The website cache will be refreshed. All published content will be updated, while unpublished content will stay unpublished. + The website cache has been refreshed. All publish content is now up to date. While all + unpublished content is still unpublished + + The website cache will be refreshed. All published content will be updated, while + unpublished content will stay unpublished. + Number of columns Number of rows Click on the image to see full size @@ -505,14 +560,15 @@ Select editor Select configuration Select snippet - This will delete the node and all its languages. If you only want to delete one language, you should unpublish the node in that language instead. + This will delete the node and all its languages. If you only want to delete one + language, you should unpublish the node in that language instead. + %0%.]]> %0% from the %1% group]]> Yes, remove There are no dictionary items. - Create dictionary item Configured Searchers - Shows properties and tools for any configured Searcher (i.e. such as a multi-index searcher) + Shows properties and tools for any configured Searcher (i.e. such as a + multi-index searcher) + Field values Health status The health status of the index and if it can be read @@ -534,7 +592,9 @@ Index info Lists the properties of the index Manage Examine's indexes - Allows you to view the details of each index and provides some tools for managing the indexes + Allows you to view the details of each index and provides some tools for + managing the indexes + Rebuild index @@ -548,7 +608,9 @@ Tools to manage the index fields The index cannot be read and will need to be rebuilt - The process is taking longer than expected, check the Umbraco log to see if there have been any errors during this operation + The process is taking longer than expected, check the Umbraco log to see if there + have been any errors during this operation + This index cannot be rebuilt because it has no assigned IIndexPopulator @@ -600,16 +662,25 @@ Select the folder to move to in the tree structure below was moved underneath - %0% will delete the properties and their data from the following items]]> - I understand this action will delete the properties and data based on this Data Type + + %0% will delete the properties and their data from the following items]]> + I understand this action will delete the properties and data based on this Data + Type + - Your data has been saved, but before you can publish this page there are some errors you need to fix first: - The current membership provider does not support changing password (EnablePasswordRetrieval need to be true) + Your data has been saved, but before you can publish this page there are some + errors you need to fix first: + + The current membership provider does not support changing password + (EnablePasswordRetrieval need to be true) + %0% already exists There were errors: There were errors: - The password should be a minimum of %0% characters long and contain at least %1% non-alpha numeric character(s) + The password should be a minimum of %0% characters long and contain at least %1% + non-alpha numeric character(s) + %0% must be an integer The %0% field in the %1% tab is mandatory %0% is a mandatory field @@ -621,13 +692,17 @@ Optimistic concurrency failure, object has been modified Received an error from the server The specified file type has been disallowed by the administrator - NOTE! Even though CodeMirror is enabled by configuration, it is disabled in Internet Explorer because it's not stable enough. + NOTE! Even though CodeMirror is enabled by configuration, it is disabled in + Internet Explorer because it's not stable enough. + Please fill both alias and name on the new property type! There is a problem with read/write access to a specific file or folder Error loading Partial View script (file: %0%) Please enter a title Please choose a type - You're about to make the picture larger than the original size. Are you sure that you want to proceed? + You're about to make the picture larger than the original size. Are you sure + that you want to proceed? + Startnode deleted, please contact your administrator Please mark content before changing style No active styles available @@ -792,6 +867,8 @@ Articles Videos Avatar for + Header + system field Blue @@ -832,19 +909,22 @@ The installer cannot connect to the database. - the documentation). Please modify the connection string manually.]]> + Could not save the web.config file. Please modify the connection string + manually. + Your database has been found and is identified as Database configuration install button to install the Umbraco %0% database ]]> - Next to proceed.]]> - Database not found! Please check that the information in the "ConnectionStrings" property in your configuration source is correct, for example, in appsettings.json (see the documentation).

    -

    To proceed, please edit your configuration source, for example, appsettings.json (see the documentation), add the connection string for your database in the key named "umbracoDbDSN".

    + + Next to proceed.]]> + Database not found! Please check that the information in the "connection string" of the "web.config" file is correct.

    +

    To proceed, please edit the "web.config" file (using Visual Studio or your favourite text editor), scroll to the bottom, add the connection string for your database in the key named "UmbracoDbDSN" and save the file.

    Click the retry button when - done.
    - More information on editing your configurations here (choose "Connection string settings").

    ]]>
    + done.
    + More information on editing web.config here.

    ]]>
    Please contact your ISP if necessary. If you're installing on a local machine or server you might need information from your system administrator.]]> @@ -857,22 +937,33 @@ ]]>
    Press Next to proceed. ]]> - next to continue the configuration wizard]]> - The Default users' password needs to be changed!]]> - The Default user has been disabled or has no access to Umbraco!

    No further actions needs to be taken. Click Next to proceed.]]> - The Default user's password has been successfully changed since the installation!

    No further actions needs to be taken. Click Next to proceed.]]> + + next to continue the configuration wizard]]> + + The Default users' password needs to be changed!]]> + + The Default user has been disabled or has no access to Umbraco!

    No further actions needs to be taken. Click Next to proceed.]]> + + The Default user's password has been successfully changed since the installation!

    No further actions needs to be taken. Click Next to proceed.]]> The password is changed! Get a great start, watch our introduction videos - By clicking the next button, you accept the license for this software as specified in the box below. Notice that this Umbraco distribution consists of two different licenses, the open source MIT license for the framework and the Umbraco freeware license that covers the UI. + By clicking the next button (or modifying the umbracoConfigurationStatus in web.config), + you accept the license for this software as specified in the box below. Notice that this Umbraco distribution + consists of two different licenses, the open source MIT license for the framework and the Umbraco freeware license + that covers the UI. + Not installed yet. Affected files and folders More information on setting up permissions for Umbraco here - You need to grant ASP.NET modify permissions to the following files/folders + You need to grant ASP.NET modify permissions to the following + files/folders + Your permission settings are almost perfect!

    You can run Umbraco without problems, but you will not be able to install packages which are recommended to take full advantage of Umbraco.]]>
    How to Resolve Click here to read the text version - video tutorial on setting up folder permissions for Umbraco or read the text version.]]> + + video tutorial on setting up folder permissions for Umbraco or read the text version.]]> Your permission settings might be an issue!

    You can run Umbraco without problems, but you will not be able to create folders or install packages which are recommended to take full advantage of Umbraco.]]>
    @@ -882,7 +973,9 @@ Your permission settings are perfect!

    You are ready to run Umbraco and install packages!]]>
    Resolving folder issue - Follow this link for more information on problems with ASP.NET and creating folders + Follow this link for more information on problems with ASP.NET and + creating folders + Setting up folder permissions Further help and information Get help from our award winning community, browse the documentation or watch some free videos on how to build a simple site, how to use packages and a quick guide to the Umbraco terminology]]> Umbraco %0% is installed and ready for use - + /web.config file and update the AppSetting key UmbracoConfigurationStatus in the bottom to the value of '%0%'.]]> started instantly by clicking the "Launch Umbraco" button below.
    If you are new to Umbraco, you can find plenty of resources on our getting started pages.]]>
    Launch Umbraco @@ -949,7 +1043,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Happy super Sunday - Happy manic Monday + Happy manic Monday Happy tubular Tuesday Happy wonderful Wednesday Happy thunderous Thursday @@ -958,10 +1052,15 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Log in below Sign in with Session timed out - © 2001 - %0%
    Umbraco.com

    ]]>
    + + © 2001 - %0%
    Umbraco.com

    ]]>
    Forgotten password? - An email will be sent to the address specified with a link to reset your password - An email with password reset instructions will be sent to the specified address if it matched our records + An email will be sent to the address specified with a link to reset your + password + + An email with password reset instructions will be sent to the + specified address if it matched our records + Show password Hide password Return to login form @@ -1067,7 +1166,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont The current node is not allowed under the chosen node because of its type The current node cannot be moved to one of its subpages The current node cannot exist at the root - The action isn't allowed since you have insufficient permissions on 1 or more child documents. + The action isn't allowed since you have insufficient permissions on 1 or more child + documents. + Relate copied items to original @@ -1187,13 +1288,15 @@ To manage your website, simply open the Umbraco backoffice and start adding cont This package has no configuration view No packages have been created yet You don’t have any packages installed - 'Packages' icon in the top right of your screen]]> + + 'Packages' icon in the top right of your screen]]> Package Content License Search for packages Results for We couldn’t find anything for - Please try searching for another package or browse through the categories + Please try searching for another package or browse through the categories + Popular New releases has @@ -1207,7 +1310,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Downloads Likes Compatibility - This package is compatible with the following versions of Umbraco, as reported by community members. Full compatability cannot be guaranteed for versions reported below 100% + This package is compatible with the following versions of Umbraco, as + reported by community members. Full compatability cannot be guaranteed for versions reported below 100% + External sources Author Documentation @@ -1234,7 +1339,10 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Paste with full formatting (Not recommended) - The text you're trying to paste contains special characters or formatting. This could be caused by copying text from Microsoft Word. Umbraco can remove special characters or formatting automatically, so the pasted content will be more suitable for the web. + The text you're trying to paste contains special characters or formatting. This could be + caused by copying text from Microsoft Word. Umbraco can remove special characters or formatting automatically, so + the pasted content will be more suitable for the web. + Paste as raw text without any formatting at all Paste, but remove formatting (Recommended) @@ -1250,7 +1358,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Login Page Choose the page that contains the login form Remove protection... - %0%?]]> + + %0%?]]> Select the pages that contain login form and error messages %0%]]> %0%]]> @@ -1277,8 +1386,11 @@ To manage your website, simply open the Umbraco backoffice and start adding cont - - Validation failed for required language '%0%'. This language was saved but not published. + + + Validation failed for required language '%0%'. This + language was saved but not published. + Publishing in progress - please wait... %0% out of %1% pages have been published... %0% has been published @@ -1306,7 +1418,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Edit %0% on %1% Discard creation? - You have made changes to this content. Are you sure you want to discard them? + You have made changes to this content. Are you sure you want to + discard them? + Remove all medias? Clipboard Not allowed @@ -1331,9 +1445,12 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Created Select a version to compare with the current version Current version - Red text will not be shown in the selected version. , green means added]]> + + Red text will not be shown in the selected version. , green means added]]> Document has been rolled back - This displays the selected version as HTML, if you wish to see the difference between 2 versions at the same time, use the diff view + This displays the selected version as HTML, if you wish to see the difference between 2 + versions at the same time, use the diff view + Rollback to Select version View @@ -1359,7 +1476,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Default template - To import a Document Type, find the ".udt" file on your computer by clicking the "Browse" button and click "Import" (you'll be asked for confirmation on the next screen) + To import a Document Type, find the ".udt" file on your computer by clicking the + "Browse" button and click "Import" (you'll be asked for confirmation on the next screen) + New Tab Title Node type Type @@ -1370,7 +1489,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Tabs Master Content Type enabled This Content Type uses - No properties defined on this tab. Click on the "add a new property" link at the top to create a new property. + No properties defined on this tab. Click on the "add a new property" link at + the top to create a new property. + Create matching template Add icon @@ -1378,7 +1499,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Sort order Creation date Sorting complete. - Drag the different items up or down below to set how they should be arranged. Or click the column headers to sort the entire collection of items + Drag the different items up or down below to set how they should be arranged. Or click the + column headers to sort the entire collection of items + This node has no child nodes to sort @@ -1408,7 +1531,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont and is visible on the website %0% documents published and visible on the website %0% published and visible on the website - %0% documents published for languages %1% and visible on the website + %0% documents published for languages %1% and visible on the website + Content saved Remember to publish to make changes visible A schedule for publishing has been updated @@ -1436,13 +1560,16 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Media Type saved Member Type saved Member Group saved + Another Member Group with the same name already exists Template not saved Please make sure that you do not have 2 templates with the same alias Template saved Template saved without any errors! Content unpublished Content variation %0% unpublished - The mandatory language '%0%' was unpublished. All languages for this content item are now unpublished. + The mandatory language '%0%' was unpublished. All languages for this + content item are now unpublished. + Partial view saved Partial view saved without any errors! Partial view not saved @@ -1462,23 +1589,34 @@ To manage your website, simply open the Umbraco backoffice and start adding cont User %0% was deleted Invite user Invitation has been re-sent to %0% - Cannot publish the document since the required '%0%' is not published + Cannot publish the document since the required '%0%' is not published + Validation failed for language '%0%' Document Type was exported to file An error occurred while exporting the Document Type The release date cannot be in the past - Cannot schedule the document for publishing since the required '%0%' is not published - Cannot schedule the document for publishing since the required '%0%' has a publish date later than a non mandatory language + Cannot schedule the document for publishing since the required '%0%' is not + published + + Cannot schedule the document for publishing since the required '%0%' has a + publish date later than a non mandatory language + The expire date cannot be in the past The expire date cannot be before the release date - Domains are not configured for multilingual site, please contact an administrator, see log for more information - There is no domain configured for %0%, please contact an administrator, see log for more information + Domains are not configured for multilingual site, please contact an administrator, + see log for more information + + There is no domain configured for %0%, please contact an administrator, see + log for more information + Add style Edit style Rich text editor styles - Define the styles that should be available in the rich text editor for this stylesheet + Define the styles that should be available in the rich text editor for this + stylesheet + Edit stylesheet Edit stylesheet property The name displayed in the editor style selector @@ -1500,20 +1638,24 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Insert Choose what to insert into your template Dictionary item - A dictionary item is a placeholder for a translatable piece of text, which makes it easy to create designs for multilingual websites. + A dictionary item is a placeholder for a translatable piece of text, which + makes it easy to create designs for multilingual websites. + Macro - A Macro is a configurable component which is great for - reusable parts of your design, where you need the option to provide parameters, - such as galleries, forms and lists. - + A Macro is a configurable component which is great for + reusable parts of your design, where you need the option to provide parameters, + such as galleries, forms and lists. +
    Value - Displays the value of a named field from the current page, with options to modify the value or fallback to alternative values. + Displays the value of a named field from the current page, with options to modify + the value or fallback to alternative values. + Partial view - A partial view is a separate template file which can be rendered inside another - template, it's great for reusing markup or for separating complex templates into separate files. - + A partial view is a separate template file which can be rendered inside another + template, it's great for reusing markup or for separating complex templates into separate files. + Master template No master Render child template @@ -1585,7 +1727,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Click to insert macro Write here... Grid Layouts - Layouts are the overall work area for the grid editor, usually you only need one or two different layouts + Layouts are the overall work area for the grid editor, usually you only need one or + two different layouts + Add Grid Layout Edit Grid Layout Adjust the layout by setting column widths and adding additional sections @@ -1611,31 +1755,49 @@ To manage your website, simply open the Umbraco backoffice and start adding cont are added You are deleting the row configuration - Deleting a row configuration name will result in loss of data for any existing content that is based on this configuration. - + Deleting a row configuration name will result in loss of data for any existing content that is based on this + configuration. + + You are deleting the layout + Modifying a layout will result in loss of data for any existing content that is based + on this configuration. + Compositions Group - You can't move the group %0% to this tab because the group will get the same alias as a tab: "%1%". Rename the group to continue. + You can't move the group %0% to this tab because the group will get the same + alias as a tab: "%1%". Rename the group to continue. + You have not added any groups Add group Inherited from Add property Required label Enable list view - Configures the content item to show a sortable and searchable list of its children, the children will not be shown in the tree + Configures the content item to show a sortable and searchable list of its + children, the children will not be shown in the tree + Allowed Templates - Choose which templates editors are allowed to use on content of this type + Choose which templates editors are allowed to use on content of this type + Allow as root - Allow editors to create content of this type in the root of the content tree. + Allow editors to create content of this type in the root of the content tree. + Allowed child node types - Allow content of the specified types to be created underneath content of this type. + Allow content of the specified types to be created underneath content of this + type. + Choose child node - Inherit tabs and properties from an existing Document Type. New tabs will be added to the current Document Type or merged if a tab with an identical name exists. - This Content Type is used in a composition, and therefore cannot be composed itself. + Inherit tabs and properties from an existing Document Type. New tabs will be + added to the current Document Type or merged if a tab with an identical name exists. + + This Content Type is used in a composition, and therefore cannot be composed itself. + There are no Content Types available to use as a composition. - Removing a composition will delete all the associated property data. Once you save the Document Type there's no way back. + Removing a composition will delete all the associated property data. Once you + save the Document Type there's no way back. + Create new Use existing Editor settings @@ -1651,21 +1813,33 @@ To manage your website, simply open the Umbraco backoffice and start adding cont All Document Types All Documents All media items - using this Document Type will be deleted permanently, please confirm you want to delete these as well. - using this Media Type will be deleted permanently, please confirm you want to delete these as well. - using this Member Type will be deleted permanently, please confirm you want to delete these as well + using this Document Type will be deleted permanently, please confirm you want to + delete these as well. + + using this Media Type will be deleted permanently, please confirm you want to delete + these as well. + + using this Member Type will be deleted permanently, please confirm you want to delete + these as well + and all documents using this type and all media items using this type and all members using this type Member can edit - Allow this property value to be edited by the member on their profile page + Allow this property value to be edited by the member on their profile page + Is sensitive data - Hide this property value from content editors that don't have access to view sensitive information + Hide this property value from content editors that don't have access to view + sensitive information + Show on member profile - Allow this property value to be displayed on the member profile page + Allow this property value to be displayed on the member profile page + tab has no sort order Where is this composition used? - This composition is currently used in the composition of the following Content Types: + This composition is currently used in the composition of the following + Content Types: + Allow variations Allow vary by culture Allow segmentation @@ -1678,31 +1852,45 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Allow segmentation Element Type Is an Element Type - An Element Type is meant to be used for instance in Nested Content, and not in the tree. - A Document Type cannot be changed to an Element Type once it has been used to create one or more content items. + An Element Type is meant to be used for instance in Nested Content, and not in the + tree. + + A Document Type cannot be changed to an Element Type once it has been used to + create one or more content items. + This is not applicable for an Element Type You have made changes to this property. Are you sure you want to discard them? Appearance Label above (full-width) %0%?]]> - %0%?]]> - %0%?]]> + + %0%?]]> + + %0%?]]> This will also delete all items below this tab. This will also delete all items below this group. Add tab Convert to tab Drag properties here to place directly on the tab + You are removing the child node + Removing a child node will limit the editors options to create different content + types beneath a node. + Add language Mandatory language - Properties on this language have to be filled out before the node can be published. + Properties on this language have to be filled out before the node can be + published. + Default language An Umbraco site can only have one default language set. Switching default language may result in default content missing. Falls back to No fall back language - To allow multi-lingual content to fall back to another language if not present in the requested language, select it here. + To allow multi-lingual content to fall back to another language if not + present in the requested language, select it here. + Fall back language none @@ -1773,13 +1961,17 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Cheers from the Umbraco robot ]]> - No translator users found. Please create a translator user before you start sending content to translation + No translator users found. Please create a translator user before you start sending + content to translation + The page '%0%' has been send to translation Send the page '%0%' to translation Total words Translate to Translation completed. - You can preview the pages, you've just translated, by clicking below. If the original page is found, you will get a comparison of the 2 pages. + You can preview the pages, you've just translated, by clicking below. If the + original page is found, you will get a comparison of the 2 pages. + Translation failed, the XML file might be corrupt Translation options Translator @@ -1832,7 +2024,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Access - Based on the assigned groups and start nodes, the user has access to the following nodes + Based on the assigned groups and start nodes, the user has access to the following nodes + Assign access Administrator Category field @@ -1845,10 +2038,14 @@ To manage your website, simply open the Umbraco backoffice and start adding cont hasn't been locked out The password hasn't been changed Confirm new password - You can change your password for accessing the Umbraco backoffice by filling out the form below and click the 'Change Password' button + You can change your password for accessing the Umbraco backoffice by filling + out the form below and click the 'Change Password' button + Content Channel Create another user - Create new users to give them access to Umbraco. When a new user is created a password will be generated that you can share with the user. + Create new users to give them access to Umbraco. When a new user is created a password + will be generated that you can share with the user. + Description field Disable User Document Type @@ -1859,7 +2056,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Go to user profile Add groups to assign access and permissions Invite another user - Invite new users to give them access to Umbraco. An invite email will be sent to the user with information on how to log in to Umbraco. Invites last for 72 hours. + Invite new users to give them access to Umbraco. An invite email will be sent to the + user with information on how to log in to Umbraco. Invites last for 72 hours. + Language Set the language you will see in menus and dialogs Last lockout date @@ -1883,7 +2082,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Your new password cannot be blank! Current password Invalid current password - There was a difference between the new password and the confirmed password. Please try again! + There was a difference between the new password and the confirmed password. Please + try again! + The confirmed password doesn't match the new password! The password must have at least one digit ('0'-'9') The password must have at least one lowercase ('a'-'z') @@ -1910,7 +2111,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Limit the content tree to specific start nodes User last updated has been created - The new user has successfully been created. To log in to Umbraco use the password below. + The new user has successfully been created. To log in to Umbraco use the + password below. + The user already has a password set The user is already in group '%0%' Lockout is not enabled for this user @@ -1920,10 +2123,18 @@ To manage your website, simply open the Umbraco backoffice and start adding cont User permissions User group has been invited - An invitation has been sent to the new user with details about how to log in to Umbraco. - Hello there and welcome to Umbraco! In just 1 minute you’ll be good to go, we just need you to setup a password and add a picture for your avatar. - Welcome to Umbraco! Unfortunately your invite has expired. Please contact your administrator and ask them to resend it. - Uploading a photo of yourself will make it easy for other users to recognize you. Click the circle above to upload your photo. + An invitation has been sent to the new user with details about how to log in to + Umbraco. + + Hello there and welcome to Umbraco! In just 1 minute you’ll be good to go, we + just need you to setup a password and add a picture for your avatar. + + Welcome to Umbraco! Unfortunately your invite has expired. Please contact your + administrator and ask them to resend it. + + Uploading a photo of yourself will make it easy for other users to recognize + you. Click the circle above to upload your photo. + Writer Change Your profile @@ -2085,14 +2296,19 @@ To manage your website, simply open the Umbraco backoffice and start adding cont 3: Configuration file path --> Value is set to the recommended value: '%0%'. - Expected value '%1%' for '%2%' in configuration file '%3%', but found '%0%'. - Found unexpected value '%0%' for '%2%' in configuration file '%3%'. + Expected value '%1%' for '%2%' in configuration file '%3%', but + found '%0%'. + + Found unexpected value '%0%' for '%2%' in configuration file '%3%'. + MacroErrors are set to '%0%'. - MacroErrors are set to '%0%' which will prevent some or all pages in your site from loading completely if there are any errors in macros. Rectifying this will set the value to '%1%'. + MacroErrors are set to '%0%' which will prevent some or all pages in + your site from loading completely if there are any errors in macros. Rectifying this will set the value to '%1%'. + Debug compilation mode is disabled. - Debug compilation mode is currently enabled. It is recommended to disable this setting before go live. + Debug compilation mode is currently enabled. It is recommended to + disable this setting before go live. + @@ -2119,30 +2342,48 @@ To manage your website, simply open the Umbraco backoffice and start adding cont - X-Frame-Options used to control whether a site can be IFRAMEd by another was found.]]> - X-Frame-Options used to control whether a site can be IFRAMEd by another was not found.]]> - X-Content-Type-Options used to protect against MIME sniffing vulnerabilities was found.]]> - X-Content-Type-Options used to protect against MIME sniffing vulnerabilities was not found.]]> - Strict-Transport-Security, also known as the HSTS-header, was found.]]> - Strict-Transport-Security was not found.]]> + + X-Frame-Options used to control whether a site can be IFRAMEd by another was found.]]> + + X-Frame-Options used to control whether a site can be IFRAMEd by another was not found.]]> + + X-Content-Type-Options used to protect against MIME sniffing vulnerabilities was found.]]> + + X-Content-Type-Options used to protect against MIME sniffing vulnerabilities was not found.]]> + + Strict-Transport-Security, also known as the HSTS-header, was found.]]> + + Strict-Transport-Security was not found.]]> X-XSS-Protection was found.]]> - X-XSS-Protection was not found.]]> + + X-XSS-Protection was not found.]]> - %0%.]]> - No headers revealing information about the website technology were found. - the documentation), Umbraco:CMS:Global:Smtp could not be found.]]> - the documentation) Umbraco:CMS:Global:Smtp section, the host is not configured.]]> - SMTP settings are configured correctly and the service is operating as expected. - the documentation) is correct in the Umbraco:CMS:Global:Smtp section.]]> - %0%.]]> - %0%.]]> -

    Results of the scheduled Umbraco Health Checks run on %0% at %1% are as follows:

    %2%]]>
    + + %0%.]]> + No headers revealing information about the website technology were found. + + The 'Umbraco:CMS:Global:Smtp' configuration could not be found. + The 'Umbraco:CMS:Global:Smtp:Host' configuration could not be + found. + + SMTP settings are configured correctly and the service is operating + as expected. + + The SMTP server configured with host '%0%' and port '%1%' could not be + reached. Please check to ensure the SMTP settings in the configuration 'Umbraco:CMS:Global:Smtp' are correct. + + + %0%.]]> + + %0%.]]> + +

    Results of the scheduled Umbraco Health Checks run on %0% at %1% are as follows:

    %2%]]>
    Umbraco Health Check Status: %0% Check group - The health checker evaluates various areas of your site for best practice settings, configuration, potential problems, etc. You can easily fix problems by pressing a button. You can add your own health checks, have a look at the documentation for more information about custom health checks.

    ]]> @@ -2157,7 +2398,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Redirect URL Management The following URLs redirect to this content item: No redirects have been made - When a published page gets renamed or moved a redirect will automatically be made to the new page. + When a published page gets renamed or moved a redirect will automatically be + made to the new page. + Redirect URL removed. Error removing redirect URL. This will remove the redirect @@ -2178,7 +2421,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Trashed content with Id: {0} related to original parent content with Id: {1} Trashed media with Id: {0} related to original parent media item with Id: {1} Cannot automatically restore this item - There is no location where this item can be automatically restored. You can move the item manually using the tree below. + There is no location where this item can be automatically restored. You + can move the item manually using the tree below. + was restored under @@ -2248,8 +2493,10 @@ To manage your website, simply open the Umbraco backoffice and start adding cont View more options Search the Umbraco backoffice Search for content nodes, media nodes etc. across the backoffice. - When autocomplete results are available, press up and down arrows, or use the tab key and use the enter key to select. - Path: + When autocomplete results are available, press up and down arrows, or use the + tab key and use the enter key to select. + + Path: Found in Has translation Missing translation @@ -2265,7 +2512,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont This Data Type has no references. Used in Document Types Used in Media Types - Used in Member Types + Used in Member Types Used by Used in Documents Used in Members @@ -2274,8 +2521,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Delete Saved Search Log Levels - Select all - Deselect all + Select all + Deselect all Saved Searches Save Search Enter a friendly name for your search query @@ -2328,11 +2575,10 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Close Property Actions - Wait Refresh status Memory Cache - Reload Database Cache - Rebuilding can be expensive. Use it when reloading is not enough, and you think that the database cache has not been @@ -2353,7 +2599,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Rebuild Internals - not need to use it. ]]> @@ -2365,7 +2611,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Performance profiling - Umbraco currently runs in debug mode. This means you can use the built-in performance profiler to assess the performance when rendering pages.

    @@ -2382,14 +2628,14 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Activate the profiler by default Friendly reminder - - You should never let a production site run in debug mode. Debug mode is turned off by setting Umbraco:CMS:Hosting:Debug to false in appsettings.json, appsettings.{Environment}.json or via an environment variable. + You should never let a production site run in debug mode. Debug mode is turned off by setting Umbraco:CMS:Hosting:Debug to false in appsettings.json, appsettings.{Environment}.json or via an environment variable.

    ]]>
    - Umbraco currently does not run in debug mode, so you can't use the built-in profiler. This is how it should be for a production site.

    @@ -2402,7 +2648,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Hours of Umbraco training videos are only a click away - Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit umbraco.tv for even more Umbraco videos

    ]]>
    @@ -2410,41 +2656,48 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Start here - This section contains the building blocks for your Umbraco site. Follow the below links to find out more about working with the items in the Settings section + This section contains the building blocks for your Umbraco site. Follow the below + links to find out more about working with the items in the Settings section + Find out more - in the Documentation section of Our Umbraco ]]> - Community Forum ]]> - tutorial videos (some are free, some require a subscription) ]]> - productivity boosting tools and commercial support ]]> - training and certification opportunities ]]> Welcome to The Friendly CMS - Thank you for choosing Umbraco - we think this could be the beginning of something beautiful. While it may feel overwhelming at first, we've done a lot to make the learning curve as smooth and fast as possible. + Thank you for choosing Umbraco - we think this could be the beginning of something + beautiful. While it may feel overwhelming at first, we've done a lot to make the learning curve as smooth and fast + as possible. + Umbraco Forms - Create forms using an intuitive drag and drop interface. From simple contact forms that sends e-mails to advanced questionaires that integrate with CRM systems. Your clients will love it! + Create forms using an intuitive drag and drop interface. From simple contact forms + that sends e-mails to advanced questionaires that integrate with CRM systems. Your clients will love it! + Pick Element Type @@ -2464,14 +2717,20 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Label Custom view Show custom view description - Overwrite how this block appears in the backoffice UI. Pick a .html file containing your presentation. + Overwrite how this block appears in the backoffice UI. Pick a .html file + containing your presentation. + Settings model Overlay editor size Add custom view Add settings - %0%?]]> - %0%?]]> - The content of this block will still be present, editing of this content will no longer be available and will be shown as unsupported content. + + %0%?]]> + + %0%?]]> + The content of this block will still be present, editing of this content + will no longer be available and will be shown as unsupported content. + Thumbnail Add thumbnail @@ -2491,10 +2750,12 @@ To manage your website, simply open the Umbraco backoffice and start adding cont What are Content Templates? - Content Templates are pre-defined content that can be selected when creating a new content node. + Content Templates are pre-defined content that can be selected when creating a new + content node. + How do I create a Content Template? - There are two ways to create a Content Template:

    • Right-click a content node and select "Create Content Template" to create a new Content Template.
    • @@ -2504,7 +2765,10 @@ To manage your website, simply open the Umbraco backoffice and start adding cont ]]> How do I manage Content Templates? - You can edit and delete Content Templates from the "Content Templates" tree in the Settings section. Expand the Document Type which the Content Template is based on and click it to edit or delete it. + You can edit and delete Content Templates from the "Content Templates" tree in the + Settings section. Expand the Document Type which the Content Template is based on and click it to edit or delete + it. + End @@ -2512,11 +2776,15 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Preview website Open website in preview mode Preview website? - You have ended preview mode, do you want to enable it again to view the latest saved version of your website? + You have ended preview mode, do you want to enable it again to view the + latest saved version of your website? + Preview latest version View published version View published version? - You are in Preview Mode, do you want exit in order to view the published version of your website? + You are in Preview Mode, do you want exit in order to view the + published version of your website? + View published version Stay in preview mode diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/es.xml b/src/Umbraco.Web.UI/umbraco/config/lang/es.xml index 3fb0af237773..df78683acab4 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/es.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/es.xml @@ -194,7 +194,7 @@ Raíz de contenido - Crear nueva Plantilla de Contenido desde '%0%' + %0%]]> Vacía Seleccionar Plantilla de Contenido Plantilla de Contenido creada diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml b/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml index cfd6c05d4902..786104e6e57d 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml @@ -136,6 +136,7 @@ Sauver la mise en page de la liste Planifier Prévisualiser + Prévisualiser La prévisualisation est désactivée car aucun modèle n'a été assigné. Choisir un style Afficher les styles @@ -276,7 +277,7 @@ Copier du clipboard - Créer un nouveau Modèle de Contenu à partir de '%0%' + %0%]]> Vide Sélectionner un Modèle de Contenu Modèle de Contenu créé @@ -1346,6 +1347,7 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Type de média sauvegardé Type de membre sauvegardé Groupe de membres sauvegardé + Un autre groupe de membres existe déjà avec le même nom Modèle non sauvegardé Assurez-vous de ne pas avoir 2 modèles avec le même alias. Modèle sauvegardé @@ -2122,7 +2124,6 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Ouvrir les Property Actions - Attendez Rafraîchir le Statut Cache Mémoire diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/it.xml b/src/Umbraco.Web.UI/umbraco/config/lang/it.xml index ef5136134316..a0d89bff2df4 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/it.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/it.xml @@ -8,12 +8,18 @@ Gestisci hostnames Audit Trail Sfoglia + Cambia tipo di documento + Cambia tipo di dato Copia Crea + Esporta Crea pacchetto + Crea gruppo Cancella Disabilita + Modifica impostazioni Svuota il cestino + Abilita Esporta il tipo di documento Importa il tipo di documento Importa il pacchetto @@ -23,40 +29,98 @@ Notifiche Accesso pubblico Pubblica - Aggiorna nodi + Non pubblicare + Aggiorna Ripubblica intero sito + Rimuovi + Rinomina + Ripristina + Imposta i permessi per la pagina %0% + Scegli dove copiare + Scegli dove muovere + nella struttura sottostante + Scegli dove copiare l'oggetto/gli oggetti selezionati + Scegli dove spostare l'oggetto/gli oggetti selezionati + + + Permessi Annulla ultima modifica Invia per la pubblicazione Invia per la traduzione + Crea gruppo Ordina Traduci - Annulla pubblicazione Aggiorna - Rimuovi - Ripristina - Crea Content Template - Crea gruppo + Imposta permessi + Sblocca + Crea modello di contenuto + Invia nuovamente l'invito + + + Contenuto + Amministrazione + Struttura + Altro + + + Consenti l'accesso per assegnare gli hostnames + Consenti l'accesso per visualizzare la cronologia di un nodo + Consenti l'accesso per visualizzare un nodo + Consenti l'accesso per cambiare tipo di documento a un nodo + Consenti l'accesso per copiare un nodo + Consenti l'accesso per creare i nodi + Consenti l'accesso per eliminare i nodi + Consenti l'accesso per spostare un nodo + Consenti l'accesso per impostare e cambiare le restrizioni di accesso a un nodo + Consenti l'accesso per pubblicare un nodo + Consenti l'accesso per non pubblicare un nodo + Consenti l'accesso per cambiare i permessi di un nodo + Consenti l'accesso per riportare un nodo a una versione precedente + Consenti l'accesso per inviare un nodo in approvazione prima di pubblicare + Consenti l'accesso per inviare un nodo per la traduzione + Consenti l'accesso per cambiare l'ordinamento dei nodi + Consenti l'accesso per tradurre un nodo + Consenti l'accesso per salvare un nodo + Consenti l'accesso per creare un modello di contenuto + + + Contenuto + Info + Permesso negato. Aggiungi nuovo dominio + rimuovi + Nodo non valido. + + + Lingua Dominio - Hostname non valido Modifica il dominio corrente - - - Visualizzazione per - Contenuto pubblicato - Contenuto salvato + + + + Eredita + Lingua + + oppure eredita la lingua dai nodi padre. Si applicherà anche
      + al nodo corrente, a meno che un dominio sotto non venga applicato.]]> +
      + Domini + Cancella selezione + Seleziona + Fai qualcos'altro Grassetto Cancella rientro paragrafo - Inserisci dal file + Inserisci campo del form Inserisci intestazione grafica Modifica Html Inserisci rientro paragrafo @@ -70,73 +134,308 @@ Elenco numerato Inserisci macro Inserisci immagine + Pubblica e chiudi + Pubblica con discendenti Modifica relazioni + Ritorna alla lista Salva + Salva e chiudi Salva e pubblica + Salva e pianifica Salva e invia per approvazione - Anteprima - - Scegli lo stile - Mostra gli stili - Inserisci tabella - Altre azioni - Pubblica con i discendenti + Salva list view Pianifica - Seleziona - Annulla selezione + Anteprima + Salva e visualizza anteprima + + Scegli stile + Vedi stili + Inserisci tabella + Genera modelli e chiudi + Salva e genera modelli + Indietro + Avanti + Ripristina + Elimina tag + Cancella + Conferma + + Invia + Invia e chiudi + + + Visualizzazione per + Contenuto eliminato + Contenuto non pubblicato + Contenuto non pubblicato per le lingue: %0% + Contenuto pubblicato + Contenuto pubblicato per le lingue: %0% + Contenuto salvato + Contenuto salvato per le lingue: %0% + Contenuto spostato + Contenuto copiato + Contenuto ripristinato + Contenuto inviato per l'approvazione + Contenuto inviato per l'approvazione per le lingue: %0% + Ordina gli elementi figlio eseguito dall'utente + %0% + Copia + Pubblica + Pubblica + Sposta + Salva + Salva + Elimina + Non pubblicare + Non pubblicare + Ripristina + Invia per l'approvazione + Invia per l'approvazione + Ordina + Personalizzato + Cronologia (tutte le varianti) + + + Impossibile creare una cartella sotto genitore con ID %0% + Impossibile creare una cartella sotto genitore con nome %0% + + + Impossibile eliminare l'elemento: %0% + Pubblicato Informazioni su questa pagina - Link alternativo - + Alias + (come descriveresti l'immagine via telefono) Links alternativi Clicca per modificare questo elemento Creato da + Autore originale + Aggiornato da Creato il + Tipo di documento Modifica Attivo fino al Ultima pubblicazione - Link ai media + Non ci sono elementi da visualizzare + Non ci sono elementi da visualizzare nella lista. + + Tipo di media + Link ai media Gruppo di membri Ruolo - Tipologia Membro + Tipo di Membro + Non sono state effettuate modifiche Titolo della Pagina + Questo media non ha link + - - Pubblicato + + + + + + Impossibile ottenere l'URL + + + + + Pubblica + Pubblicato + Pubblicato (modifiche in sospeso) Stato della pubblicazione + + %0% e tutti gli elementi sottostanti, rendendo così il loro contenuto pubblicamente disponibile.]]> + + Pubblicato il + Non pubblicato il Rimuovi data + Imposta data Ordinamento dei nodi aggiornato - + + Statistiche Titolo (opzionale) + Testo alternativo (opzionale) + Didascalia (opzionale) Tipo Non pubblicare + Bozza + Non creato Ultima modifica - Rimuovi il file + + Rimuovi file(s) + Clicca qui per rimuovere l'immagine dal media + Clicca qui per rimuovere il file dal media Link al documento - Elementi - Pubblicato - Seleziona da data e l'ora in cui pubblicare/depubblicare il contenuto. - Imposta data - Depubblicato il + Membro del gruppo/i + Non un membro del gruppo/i + Elementi figli + Target + Questo si traduce nella seguente ora sul server: + + Cosa significa questo?]]> + Sei sicuro di voler eliminare questo oggetto? + Sei sicuro di voler eliminare tutti gli oggetti? + + + + + Aggiungi Element Type + Seleziona Element Type + + + Immettere un'espressione di angular da valutare rispetto a ciascun + elemento per il relativo nome. Utilizza + + per visualizzare l'index dell'oggetto + Aggiungi un altro box di testo + Rimuovi questa text box + Root del contenuto + Includi elementi di contenuto non pubblicati. + + + + Quali lingue vorresti pubblicare? Tutte le lingue con contenuto vengono + salvate! + + Quali lingue vorresti pubblicare? + Quali lingue vorresti salvare? + Tutte le lingue con contenuto vengono salvate alla creazione! + Quali lingue vorresti inviare per l'approvazione? + Quali lingue vorresti pianificare? + Seleziona le lingue da non pubblicare. Non pubblicando una lingua obbligatoria + annullerai la pubblicazione di tutte le lingue. + + Lingue pubblicate + Lingue non pubblicate + Lingue non modificate + Queste lingue non sono state create. + + Tutte le nuove varianti verranno salvate. + Quali varianti vorresti pubblicare? + Scegli quali varianti verranno salvate. + Scegli le varianti da inviare per l'approvazione. + Imposta pubblicazione pianificata... + Seleziona le varianti da non pubblicare. Non pubblicando una lingua obbligatoria + annullerai la pubblicazione di tutte le varianti. + + Per la pubblicazione sono necessarie le seguenti varianti: + + Non siamo pronti per la pubblicazione + Pronto per la pubblicazione? + Pronto per il salvataggio? + Invia per l'approvazione + Seleziona da data e l'ora in cui pubblicare/non pubblicare il contenuto. + Crea nuovo/a + Incolla dagli appunti + + + + Crea un nuovo modello di contenuto da '%0%' + Vuoto + Seleziona un modello di contenuto + Modello di contenuto creato + + + + + + + Clicca per caricare + o clicca qui per scegliere i files + Puoi trascinare i file qui per caricarli. + Impossibile caricare questo file, non ha un tipo di file approvato + + Media root + Impossibile spostare il media + La cartella padre e di destinazione non possono essere le stesse + Impossibile copiare il media + Impossibile creare una cartella sotto l'id padre %0% + Impossibile rinominare la cartella con id %0% + Trascina e rilascia i tuoi file nell'area + + + + Crea un nuovo membro + Tutti i membri + + + + + Impossibile copiare il content type + Impossibile spostare il content type + + + Impossibile copiare il media type + Impossibile spostare il media type + Selezione automatica + + + Impossibile copiare il member type Crea un elemento sotto + Seleziona il Document Type per cui vuoi creare un modello di contenuto + Inserisci il nome della cartella Scegli il tipo ed il titolo + + Tipi di documento dentro la sezione Impostazioni, modificando Tipi di nodi figlio consentiti sotto Permessi.]]> + + Tipi di documento dentro la sezione Impostazioni.]]> + La pagina selezionata nel content tree non permette a nessuna + pagina di essere creata sotto di essa. + + Modifica permessi per questo tipo di documento + Crea un nuovo tipo di documento + + Tipi di documento dentro la sezione Impostazioni, cambiando l'opzione Consenti come root sotto Permessi.]]> + + Tipi di documento dentro la sezione Impostazioni, modificando Tipi di nodi figlio consentiti sotto Permessi.]]> + Il media selezionato non consente la creazione di altri media al di + sotto di esso. + + Modifica permessi per questo tipo di media + Tipo di documento senza template + Tipo di documento con template + + + Tipo di documento + + + Tipo di elemento + + + Composizione + + Cartella + Utilizzato per organizzare i tipi di documento, le composizioni e i tipi di elementi + creati in questo albero dei tipi di documento. + + Nuova cartella + Nuovo tipo di dato + Nuovo file JavaScript + Nuova partial view vuota + Nuova partial view macro + Nuova partial view da snippet + Nuova partial view macro da snippet + Nuova partial view macro (senza macro) + Nuovo foglio di stile + Nuovo foglio di stile per Rich Text Editor - + + hai aperto una nuova finestra Riavvia Visita @@ -146,79 +445,214 @@ Rimani Scarta le modifiche Hai delle modifiche non salvate - Sei sicuro di voler lasciare questa pagina? - hai delle modifiche non salvate + Sei sicuro di voler lasciare questa pagina? Hai delle modifiche non salvate! + + Pubblicando renderai visibli gli oggetti selezionati sul sito. + Non pubblicando rimuoverai gli oggetti selezionati e i loro discendenti dal + sito. + + Non pubblicando rimuoverai questa pagina e tutti i suoi discendenti dal sito. + + Fatto - Elimianto %0% elemento - Elimianto %0% elementi + Eliminato %0% elemento + Eliminati %0% elementi Eliminato %0% su %1% elemento - Eliminato %0% su %1% elementi + Eliminati %0% su %1% elementi Pubblicato %0% elemento - Pubblicato %0% elementi + Pubblicati %0% elementi Pubblicato %0% su %1% elemento - Pubblicato %0% su %1% elementi + Pubblicati %0% su %1% elementi %0% elemento non pubblicato %0% elementi non pubblicati - Elementi non pubblicati - %0% su %1% - Elementi non pubblicati - %0% su %1% + Elementi non pubblicati: %0% su %1% + Elementi non pubblicati: %0% su %1% Spostato %0% elemento - Spsotato %0% elementi + Spostati %0% elementi Spostato %0% su %1% elemento - Spostato %0% su %1% elementi + Spostati %0% su %1% elementi Copiato %0% elemento - Copiato %0% elementi + Copiati %0% elementi Copiato %0% su %1% elemento - Copiato %0% su %1% elementi + Copiati %0% su %1% elementi Titolo del Link Link + Ancora / querystring Nome - Gestione alias Hostnames Chiudi questa finestra - - + Sei sicuro di voler eliminare + Sei sicuro di voler disabilitare + Sei sicuro di voler rimuovere + %0%]]> + %0%]]> Taglia - Modifica elemento Dictionary - Modifica il linguaggio + Modifica elemento del Dizionario + Modifica la lingua + Modifica il media selezionato Inserisci il link locale Inserisci carattere - - + Inserisci intestazione grafica + Inserisci immagine Inserisci link Inserisci macro Inserisci tabella + + + Ultima modifica Link + Impostazioni della macro Incolla - Modifica il Permesso per - + Modifica i permessi per + Imposta i permessi per + Imposta i permessi per %0% per il gruppo di utenti %1% + Seleziona i gruppi di utenti per il quale vuoi impostare i permessi + + - regexlib.com ha attualmente qualche problema, di cui non abbiamo il controllo. Siamo spiacevoli dell'inconveniente.]]> - + + regexlib.com ha attualmente qualche problema, di cui non abbiamo il controllo. Siamo spiacevoli dell'inconveniente.]]> + + Elimina Macro Campo obbligatorio - + + Numero di colonne Numero di righe Seleziona elemento Visualizza gli elementi in cache + Relaziona con l'originale + Includi discendenti + + Link alla pagina + Apre il documento linkato in una nuova finestra o tab + Link al media + Seleziona il nodo di inizio per il contenuto + Seleziona media + Seleziona tipo di media + Seleziona icona + Seleziona oggetto + Seleziona link + Seleziona macro Seleziona contenuto + Seleziona tipo di contenuto + Seleziona il nodo di inizio per i media + Seleziona membro + Seleziona gruppo di membri + Seleziona tipo di membri + Seleziona nodo + Seleziona sezioni + Seleziona utente + Seleziona utenti + Non sono state trovate icone + Non ci sono parametri per questa macro + Non ci sono macro disponibili da inserire + Provider di accesso esterni + Exception Details + Stacktrace + Inner Exception + Linka il tuo + Togli il link al tuo + account + Seleziona editor + Seleziona configurazione + Seleziona snippet + + + %0%.]]> + %0% dal gruppo %1%]]> + Si, rimuovi + + + Non ci sono oggetti nel Dizionario. - - + %0%' qui sotto.]]> + Nome della cultura + + Panoramica del Dizionario + + + Searchers configurati + + + Valori del campo + Stato di salute + + Indexers + Index info + + Gestisci gli indexes di Examine + Permette di visualizzare i dettagli di ogni index e fornisce alcuni strumenti + per gestire gli index + + Ricostruisci index + + + A seconda della quantità di contenuti presenti nel tuo sito, potrebbe volerci un po' di tempo.
      + Non è consigliabile ricostruire un indice durante i periodi di elevato traffico del sito Web o quando gli editor modificano i contenuti. + ]]> +
      + Searchers + Cerca nell'index e visualizza i risultati + Strumenti + Strumenti per gestire l'index + Campi + + + + + IIndexPopulator + + + Inserisci il tuo username + Inserisci la tua password + Conferma la tua password + Dai un nome a %0%... + Inserisci un nome... + Inserisci un email... + Inserisci un username... + Etichetta... + Inserisci una descrizione... + Cerca... + Filtra... + Scrivi per aggiungere tags (premi invio dopo ogni tag)... + Inserisci la tua email + Inserisci un messaggio... + + #value oppure ?key=value + Inserisci un alias... + Sto generando l'alias... + Crea oggetto + Modifica + Nome + + + Crea una list view custom + Rimuovi la list view custom + + + + + Rinominato + Inserisci qui il nuovo nome della cartella + @@ -232,14 +666,30 @@ Fogli di stile collegati Visualizza etichetta Larghezza e altezza + + + + Si, elimina + + + Seleziona la cartella da spostare + nella struttura sottostante + + + %0% eliminerà le proprietà e i dati dagli oggetti seguenti]]> + + - - + + + + - + + @@ -247,46 +697,69 @@ - - - + + + + + + + + + + Errore durante il caricamento di una Partial View script (file: %0%) - - - + + + + + + - + + - Questa proprietà non è valida + + Opzioni Info Azione + Azioni Aggiungi Alias + Tutti + Indietro + Torna alla panoramica Bordo o Annulla Scegli + Pulisci Chiudi Chiudi la finestra + Chiudi il pannello Commento Conferma - Blocca le proporzioni + Vincola + Vincola le proporzioni + Contenuto Continua Copia Crea - Base di dati + Selezione di ritaglio + Database Data Default Elimina Eliminato - Elimina... + Eliminazione... Design + Dizionario Dimensioni + Scarta Scarica Modifica @@ -294,54 +767,87 @@ Elementi Email Errore + Campo Trova - Cartella + Primo + Punto focale + Generale + Gruppi + Gruppo Altezza Guida + Nascondi + Cronologia Icona + Id Importa + Includi le sottocartelle nella ricerca + Cerca solo in questa cartella + Info Inserisci Installa + Non valido Giustificato + Etichetta Lingua + Ultimo Layout + Links Caricamento Bloccato Login Log off Logout Macro + Obbligatorio + Messaggio Sposta Nome Nuovo Successivo No di + Off Ok Apri + On o + Ordina per Password Percorso Precedente - + Ricompila + Cestino + + Ricarica Rimangono + Rimuovi Rinomina Rinnova + Obbligatorio + Recupera Riprova Permessi + Pubblicazione programmata Cerca + Spiacenti, non riusciamo a trovare quello che stai cercando. + Server + Impostazioni Mostra Mostra la pagina inviata Dimensione Ordina + Stato Conferma + Riuscito Tipo Digita per cercare... + sotto Su Aggiorna Aggiornamento @@ -354,20 +860,50 @@ Benvenuto... Larghezza Si + Cartella + Risultati di ricerca Riordina - Ho finito di ordinare - Richiesto - Contenuti - Azioni - Cerca solo in questa cartella - Pianifica pubblicazione - selezionato - Annulla + Ho finito di riordinare + Anteprima Cambia password - Cronologia - Generale - Rimuovi - Gruppi + a + Vista lista + Salvataggio... + corrente + Incorpora + selezionato + Altro + Articoli + Video + Installazione + Avatar per + + + Blu + + + Aggiungi gruppo + + Aggiungi editor + Aggiungi template + Aggiungi nodo figlio + Aggiungi figlio + Modifica tipo di dato + Naviga tra le sezioni + Scorciatoie + vedi scorciatoie + Attiva/disattiva vista lista + Attiva/disattiva consenti come root + Commenta/Non commentare righe + Rimuovi riga + Copia linee sopra + Copia linee sotto + Sposta linee in su + + Generale + Editor + Attiva/disattiva consenti varianti lingua + Attiva/disattiva la segmentazione Colore di sfondo @@ -380,44 +916,98 @@ Pagina - + - installa per installare il database Umbraco %0% ]]> - Avanti per proseguire.]]> - - Premi il tasto aggiorna per aggiornare il database ad Umbraco %0%

      Non preoccuparti, il contenuto non verrà perso e tutto continuerà a funzionare dopo l'aggiornamento!

      ]]>
      - Premi il tasto Avanti per continuare.]]> - Avanti per continuare la configurazione.]]> - La password predefinita per l'utente di default deve essere cambiata!]]> - L'utente di default è stato disabilitato o non ha accesso ad Umbraco!

      Non è necessario eseguire altre operazioni. Clicca il tasto Avanti per continuare.]]> - La password è stata modificata con successo

      Non è necessario eseguire altre operazioni. Clicca il tasto Avanti per continuare.]]> + + installa per installare il database Umbraco %0% + ]]> + + + Avanti per proseguire.]]> + + + Se è necessario contatta il tuo ISP per reperire le informazioni necessarie. + Se stai effettuando l'installazione in locale o su un server, puoi richiederle al tuo amministratore di sistema.]]> + + + + Premi il tasto aggiorna per aggiornare il database ad Umbraco %0%

      +

      + Non preoccuparti, il contenuto non verrà perso e tutto continuerà a funzionare dopo l'aggiornamento! +

      + ]]> +
      + + Premi il tasto Avanti per + continuare. ]]> + + + Avanti per continuare la configurazione.]]> + + La password predefinita per l'utente di default deve essere cambiata!]]> + + L'utente di default è stato disabilitato o non ha accesso ad Umbraco!

      Non è necessario eseguire altre operazioni. Clicca il tasto Avanti per continuare.]]> + + La password dell'utente di default è stata modificata con successo

      Non è necessario eseguire altre operazioni. Clicca il tasto Avanti per continuare.]]> - - - Le impostazioni dei permessi sono perfette!

      Puoi eseguire Umbraco senza problemi, ma potresti non poter installare i pacchetti che sono consigliati per sfruttare tutti i vantaggi offerti da Umbraco.]]>
      + + + + + + La configurazione dei permessi è quasi perfetta!

      + Puoi eseguire Umbraco senza problemi, ma non sarai in grado di installare i pacchetti che sono consigliati per sfruttare a pieno le potenzialità di Umbraco.]]> +
      - video tutorial su come impostare i permessi delle cartelle per Umbraco o leggi la versione testuale.]]> - Le impostazioni dei permessi potrebbero avere dei problemi!

      Puoi eseguire Umbraco, ma potresti non essere in grado di creare cartelle o installare pacchetti che sono raccomandati per sfruttare tutti i vantaggi di Umbraco.]]>
      - Le impostazioni dei permessi non sono corrette per Umbraco!

      Per eseguire Umbraco, devi aggiornare le impostazioni dei permessi.]]>
      - La configurazione dei permessi è perfetta!

      Sei pronto per avviare Umbraco e installare i pacchetti!]]>
      - - + + video tutorial su come impostare i permessi delle cartelle per Umbraco o leggi la versione testuale.]]> + + Le impostazioni dei permessi potrebbero avere dei problemi! +

      + Puoi eseguire Umbraco senza problemi, ma non sarai in grado di creare cartelle o installare pacchetti che sono consigliati per sfruttare a pieno le potenzialità di Umbraco.]]> +
      + + Le impostazioni dei permessi non sono corrette per Umbraco! +

      + Per eseguire Umbraco, devi aggiornare le impostazioni dei permessi.]]> +
      + + La configurazione dei permessi è perfetta!

      + Sei pronto per avviare Umbraco e installare i pacchetti!]]> +
      + + + - + + + - Guarda come) Puoi anche installare eventuali Runway in un secondo momento. Vai nella sezione Developer e scegli Pacchetti.]]> - - Runway è installato + + Guarda come) + Puoi anche installare eventuali Runway in un secondo momento. Vai nella sezione Developer e scegli Pacchetti. + ]]> + + + + - Questa è la lista dei nostri moduli raccomandati, seleziona quali vorresti installare, o vedi l'intera lista di moduli - ]]> + Hai le basi. Seleziona quali moduli vorresti installare.
      + Questa è la lista dei nostri moduli raccomandati, seleziona quali vorresti installare, o vedi l'intera lista di moduli + ]]>
      Raccommandato solo per utenti esperti Vorrei iniziare da un sito semplice @@ -435,12 +1025,12 @@ ]]> - Cosa è Runway + Passo 1/5 Accettazione licenza Passo 2/5: Configurazione database Passo 3/5: Controllo permessi dei file Passo 4/5: Controllo impostazioni sicurezza - Passo 5/5: Umbraco è pronto per iniziare + Grazie per aver scelto Umbraco Naviga per il tuo nuovo sito @@ -451,7 +1041,10 @@ Hai installato Runway, quindi perché non dare uno sguardo al vostro nuovo sito Fatti aiutare dalla nostra community, consulta la documentazione o guarda alcuni video gratuiti su come costruire un semplice sito web, come usare i pacchetti e una guida rapida alla terminologia Umbraco]]> - iniziare immediatamente cliccando sul bottone "Avvia Umbraco".
      Se sei nuovo a Umbraco, si possono trovare un sacco di risorse sulle nostre pagine Getting Started.]]>
      + + iniziare immediatamente cliccando sul bottone "Avvia Umbraco".
      Se sei nuovo su Umbraco, + si possono trovare un sacco di risorse sulle nostre pagine Getting Started.]]> +
      Avvia Umbraco Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e iniziare ad aggiungere i contenuti, aggiornando i modelli e i fogli di stile o aggiungere nuove funzionalità]]> @@ -461,7 +1054,7 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in Umbraco Versione 4 Guarda - Umbraco %0% per una nuova installazione o per l'aggiornamento dalla versione 3.0. + Umbraco %0% per una nuova installazione o per l'aggiornamento dalla versione 3.0.

      Clicca "avanti" per avviare la procedura.]]>
      @@ -471,23 +1064,117 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in Nome cultura - + Riconnetti adesso per salvare il tuo lavoro - © 2001 - %0%
      umbraco.com

      ]]>
      - Buona domenica - Buon lunedì - Buon martedì - Buon mercoledì - Buon giovedì - Buon venerdì - Buon sabato + + + + + + + + Fai il login qui sotto + Fai il login con + Sessione scaduta + + © 2001 - %0%
      umbraco.com

      ]]>
      + Password dimenticata? + + + + Mostra password Nascondi password - Password dimenticata? - Una email verrà inviata all'indirizzo specificato con un link per il reset della password Ritorna alla finestra di login + Inserisci una nuova password + + + Umbraco: Reset Password + + + + + + + + + + + + +
      + + + + + +
      + +
      + +
      +
      + + + + + + +
      +
      +
      + + + + +
      + + + + +
      +

      + Reset della password richiesto +

      +

      + Il tuo username per effettuare l'accesso al backoffice di Umbraco è: %0% +

      +

      + + + + + + +
      + + Clicca questo link per resettare la password + +
      +

      +

      Se non riesci a cliccare sul link, copia e incolla questo URL nella finestra del browser:

      + + + + +
      + + %1% + +
      +

      +
      +
      +


      +
      +
      + + + ]]> +
      Dashboard @@ -496,85 +1183,204 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in Scegli la pagina sopra... - + Seleziona dove il documento %0% deve essere copiato Seleziona dove il documento %0% deve essere spostato - - - - - + + + + + + + + + + - + %0%]]> + Impostazioni di notifica salvate per + Sono state modificate le lingue seguenti %0% - Salve %0%

      - -

      Questa è un'email automatica per informare che l'azione '%1%' - è stata eseguita sulla pagina '%2%' - dall'utente '%3%' -

      - -

      -

      Riepilogo aggiornamento:

      - - %6% -
      -

      - - - -

      Buona giornata!

      - Grazie da Umbraco -

      ]]> + + + + + + + + + + + +
      + + + + + +
      + +
      + +
      +
      + + + + + + +
      +
      +
      + + + + +
      + + + + +
      +

      + Ciao %0%, +

      +

      + Questa è un'email automatica per informare che l'azione '%1%' è stata eseguita sulla pagina '%2%' dall'utente '%3%' +

      + + + + + + +
      + +
      + MODIFICA
      +
      +

      +

      Riepilogo dell'aggiornamento:

      + %6% +

      +

      + Buona giornata!

      + Saluti dal robot di Umbraco +

      +
      +
      +


      +
      +
      + + + ]]>
      - [%0%] Notifica per %1% eseguita su %2% + + Sono state modificate le seguenti lingue:

      + %0% + ]]>
      + [%0%] Notifica per %1% eseguito su %2% Notifiche + Azioni + Creati + Crea pacchetto e selezionando il pacchetto. I pacchetti Umbraco generalmente hanno l'estensione ".umb" o ".zip". ]]> + + Trascina qui caricare + Includi tutti i figli + o clicca qui per scegliere il file del pacchetto + Carica pacchetto + Installa un pacchetto locale dalla tua macchina. Installa solamente pacchetti + di cui ti fidi e ne conosci la provenienza + + Carica un altro pacchetto + Cancella e carica un altro pacchetto + Accetto + termini di servizio + Percorso del file + Percorso assoluto del file (es: /bin/umbraco.bin) + Installati + Pacchetti installati + Installa localmente + Termina + Questo pacchetto non ha una vista di configurazione + Non sono ancora stati creati pacchetti + Non hai installato nessun pacchetto + + 'Pacchetti' in alto a destra del tuo schermo]]> + Azioni del pacchetto + + Contenuto del pacchetto + Files del pacchetto + + Installa pacchetto + Licenza + URL della licenza + + Cerca un pacchetto... + Risultati per + Non abbiamo trovato niente per + Per favore prova a cercare un altro pacchetto oppure cerca tra le + categorie + + Popolari + Nuove uscite + ha + punti karma + Informazioni + Proprietario + Contributori + Creato + Versione corrente + Versione .NET + Downloads + Likes + + + + Sorgenti esterne Autore Documentazione - Meta dati pacchetto + Meta dati del pacchetto Nome del pacchetto - Il pacchetto non contiene tutti gli elementi + Il pacchetto non contiene nessun elemento
      - E' possibile rimuovere questo pacchetto dal sistema cliccando "rimuovi pacchetto" in basso.]]> + È possibile rimuovere questo pacchetto dal sistema cliccando "rimuovi pacchetto" in basso.]]>
      - Opzioni pacchetto + Opzioni del pacchetto Pacchetto leggimi - Pacchetto repository + Repository del pacchetto Conferma eliminazione @@ -585,60 +1391,154 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in perciò disinstalla con cautela. In caso di dubbio contattare l'autore del pacchetto.]]>
      Versione del pacchetto + Aggiornamento dalla versione + + + + Sto disinstallando... + Sto scaricando... + Sto importando... + Sto installando... + Sto riavviando, per favore aspetta... + + Per favore clicca 'Completa' per completare l'installazione e ricaricare la + pagina. + + Sto effettuando l'upload del pacchetto... + Verificato il funzionamento su Umbraco Cloud - + + - - usando i gruppi di membri di Umbraco.]]> - Devi creare un gruppo di membri prima di utilizzare l'autenticazione basata sui ruoli + + + Devi creare un gruppo di membri prima di utilizzare l'autenticazione basata sui + gruppi + - - - + %0%]]> + %0% è ora protetta]]> + %0%]]> - - - - - - - + + + + %0%?]]> + + + %0%]]> + %0%]]> + Protezione specifica per membri + Se vuoi controllare gli accessi per membri specifici - - - - - + Permessi insufficienti per pubblicare tutti i discendenti + + + + + + + + + + + + + + + + + + + + + + + Pubblicazione in corso, aspetta... + %0% di %1% pagine sono state pubblicate... - - - ok per pubblicare %0% e rendere questo contenuto accessibile al pubblico.

      Puoi pubblicare questa pagina e tutte le sue sottopagine selezionando pubblica tutti i figli qui sotto.]]>
      + %0% e le relative sottopagine sono state pubblicate + Pubblica %0% e tutte le sue sottopagine + + Pubblica per pubblicare %0% e quindi rendere visibile pubblicamente il suo contenuto.

      + Puoi pubblicare questa pagina e tutte le sue sottopagine spuntando Includi le sottopagine non pubblicate sotto. + ]]> +
      + + + Non hai configurato nessun colore + + + Puoi selezionare solo oggetti di tipo: %0% + Hai selezionato un elemento eliminato o nel cestino + + + + Elemento eliminato + Hai selezionato un media eliminato o nel cestino + + Eliminato + Apri nella libreria dei media + Cambia media + Resetta i tagli del media + Modifica %0% su %1% + Scartare la creazione? + + Hai fatto delle modifiche a questo contenuto. Sei sicuro di volerle + scartare? + + Rimuovere? + Rimuovere tutti i media? + Appunti + Non permesso - - - + + - - - - + Link - + inserisci la didascalia da visualizzare + Inserisci il link + + + Resetta tagio + Salva taglio + Aggiungi nuovo taglio + Fatto + Annulla modifiche + Definite dall'utente + Modifiche + Creato + Seleziona una versione da confrontare con la versione corrente - Il testo in rosso non verrà mostrato nella versione selezionata, quello in verde verrà aggiunto]]> + + Il testo in rosso non verrà mostrato nella versione selezionata, quello in verde verrà aggiunto]]> - - + + + @@ -646,102 +1546,260 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in - Concierge Contenuto - Courier - Sviluppo - Configurazione guidata Umbraco + Forms Media Membri - Newsletters + Pacchetti Impostazioni - Statistiche Traduzione Utenti + + Tours + I migliori video tutorial su Umbraco + Visita our.umbraco.com + Visita umbraco.tv + - Tipo di contenuto master abilitato - Questo tipo di contenuto usa - + + Tipo Foglio di stile + Script Tab Titolo tab Tabs + Tipo di contenuto Master abilitato + Questo tipo di contenuto usa + + + Crea un template corrispondente + Aggiungi icona Ordinamento Data creazione - - + + + + + Questo elemento non ha elementi figlio da ordinare - - - - Tipo di dati: %1%]]> - + Validazione + Gli errori di validazione devono essere sistemati prima che l'elemento possa + essere salvato + + Fallita + Salvato + Salvato. Per vedere le modifiche appena salvate ricarica la pagina + + + Cancellato + + + + Tipo di dato: %1%]]> + Tipo di documento salvato Tab creata Tab eliminata Tab con id: %0% eliminata - Contenuto non pubblicare Tipo di dato salvato - - - + + %0% documenti pubblicati e visibili sul sito web + %0% pubblicati e visibili sul sito web + %0% documenti pubblicati per le lingue %1% e visibili sul sito web + Contenuto salvato - - - + + + %0% salvata + + Le modifiche sono state inviate per l'approvazione + %0% modifiche sono state inviate per l'approvazione + Media salvato + Media salvato senza nessun errore + Membro salvato + Gruppo di Membri salvato - Tipo utente salvato + Tipo di utente salvato + Gruppo di utenti salvato + Hostnames salvati + Errore durante il salvataggio degli hostnames - + + - + + Tipo di Media salvato + Tipo di Membro salvato + Gruppo di Membri salvato + Template non salvato + Per favore controlla di non avere due templates con lo stesso alias + Template salvato + Template salvato con successo! + Contenuto non pubblicato + Variazione di contenuto %0% non pubblicata + + Partial view salvata Partial view salvata senza errori! Partial view non salvata Errore durante il salvataggio del file. - - - - + Permessi salvati per + Eliminati %0% gruppi di utenti + + Abilitati %0% utenti + Disabilitati %0% utenti + + + I gruppi di utenti sono stati assegnati + Sono stati sbloccati %0% utenti + + + + + Invita utenti + + + + Validazione fallita per la lingua '%0%' + + + + + + + + + + + - + Aggiungi stile + Modifica stile + Stili del Rich text editor + Definisci gli stili che dovranno essere disponibili nel Rich text editor per questo + foglio di stile + Anteprima + + Selettore + Stili + + Codice + Rich Text Editor - - - - - - + Impossibile eliminare il template con ID %0% + Modifica template + Sezioni + Inserisci area di contenuto + Inserisci segnaposto per l'area di contenuto + Inserisci + Scegli cosa inserire nel tuo template + Elementi del dizionario + + + Macro + + + Valore + Visualizza il valore di un campo nominato dalla pagina corrente, con delle opzioni + per modificare il valore o impostare il valore di fallback. + + Partial view + + Master template - + No master + Renderizza template figli + + @RenderBody(). + ]]> + + Definisci una sezione nominata + + @section { ... }. Questa potrà poi essere renderizzata in una + specifica area del padre di questo template, usando @RenderSection. + ]]> + + Renderizza una sezione nominata + + @RenderSection(name). + Questo renderizzerà un'area di un template figlio avvolta nel corrispondente @section [name]{ ... } definition. + ]]> + + Nome della sezione + + + @section, altrimenti verrà visualizzato un errore. + ]]> + + Generatore di query + oggetti trovati, in + copia negli appunti + Voglio + tutti i contenuti + contenuti di tipo "%0%" + da + il mio sito web + dove + e + + + prima + prima (comprese le date selezionate) + dopo + dopo (comprese le date selezionate) + + + contiene + non contiene + maggiore di + maggiore di o uguale a + minore di + minore di o uguale a + Id + Nome + Data di creazione + Ultima data di aggiornamento + ordina per + ascendente + discendente Template - Data creazione Immagine @@ -751,20 +1809,31 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in Aggiungi una riga Aggiungi contenuto Elimina contenuto - Impostazioni applicati - Questo contenuto non è consentito qui - Questo contenuto è consentito qui + Impostazioni applicate + + Clicca per incorporare - Clicca per inserire l'immagine + Clicca per inserire un immagine + Clicca per inserire una macro + Didascalia dell'immagine... Scrivi qui... I Grid Layout - I layout sono l'area globale di lavoro per il grid editor, di solito ti serve solo uno o due layout differenti + I layout sono l'area globale di lavoro per il grid editor, di solito ti servono + solamente uno o due layout differenti + Aggiungi un Grid Layout - Sistema il layout impostando la larghezza della colonna ed aggiungendo ulteriori sezioni + Modifica il Grid Layout + Sistema il layout impostando la larghezza della colonna ed aggiungendo ulteriori + sezioni + Configurazioni della riga Le righe sono le colonne predefinite disposte orizzontalmente Aggiungi configurazione della riga - Sistema la riga impostando la larghezza della colonna ed aggiungendo ulteriori colonne + Modifica configurazione della riga + Sistema la riga impostando la larghezza della colonna ed aggiungendo + ulteriori colonne + + Nessuna ulteriore configurazione disponibile Colonne Totale combinazioni delle colonne nel grid layout Impostazioni @@ -773,44 +1842,198 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in Configura i stili che possono essere cambiati dai editori Permetti tutti i editor Permetti tutte le configurazioni della riga + Oggetti massimi + Lascia vuoto o imposta a 0 per illimitati + Imposta come predefinito + Scegli aggiuntivi + Scegli predefinito + sono stati aggiunti + Attenzione + Stai eliminando le configurazioni della riga + + Eliminando un nome della configurazione della riga perderai i dati associati a qualsiasi contenuto basato su + questa configurazione. + + + + Composizioni + Gruppi + Non hai aggiunto nessun gruppo + Aggiungi gruppo + Ereditato da + + Etichetta richiesta + Abilita la vista lista + Configura l'oggetto per visualizzare una lista dei suoi figli, ordinabili e + ricercabili. I figli non saranno visualizzati nell'albero dei contenuti + + Templates abilitati + Scegli che templates sono abilitati all'utilizzo per i contenuti di questo + tipo. + + Consenti come nodo root + Consenti agli editori la creazione di questo tipo di contenuto a livello root. + + Tipi di nodi figlio consentiti + Consenti la creazione di contenuti con i tipi specificati sotto il contenuto di + questo tipo. + + Scegli nodo figlio + + + + + Non ci sono tipi di contenuto utilizzabili come composizione. + + + Crea nuovo + Usa esistente + Impostazioni dell'editor + Configurazioni disponibili + Crea una nuova configurazione + Configurazione + Si, elimina + + + Seleziona la cartella da spostare + Seleziona la cartella da copiare + nella struttura sottostante + Tutti i tipo di documento + Tutti i documenti + Tutti i media + che usano questo tipo di documento verranno eliminati permanentemente, sei sicuro di + voler eliminare anche questi? + + che usano questo tipo di media verranno eliminati permanentemente, sei sicuro di voler + eliminare anche questi? + + che usano questo tipo di membro verranno eliminati permanentemente, sei sicuro di voler + eliminare anche questi? + + e tutti i documenti che usano questo tipo + e tutti i media che usano questo tipo + e tutti i membri che usano questo tipo + + Abilita il membro alla modifica di questo valore dalla pagina del suo + profilo. + + Dati sensibili + + + Visualizza sul profilo del membro + Permette a questo valore di essere visualizzato sulla pagina del profilo + del membro + + la scheda non ha un ordine + + + + Consenti variazioni + Consenti variazioni in base alla lingua + Consenti segmentazione + Varia in base alla cultura + Varia per segmenti + Consenti agli editors la creazione di contenuto di questo tipo in lingue + differenti. + + Consenti agli editors la creazione di contenuto in diverse lingue. + Consenti agli editors la creazione di segmenti per questo contenuto. + Consenti variazioni in base alla lingua + Consenti segmentazione + Tipo di elemento + + + + + + + + + Aspetto + Etichetta sopra (larghezza intera) + + + Aggiungi lingua + Lingua obbligatoria + + + Lingua di default + + Il cambio della lingua predefinita potrebbe comportare la mancanza di + contenuti predefiniti. + + Ripiega a + Nessuna lingua alternativa + + + Lingua alternativa + nessuna + + + Aggiungi parametro + Modifica parametro + Inserisci il nome della macro + Parametri + Definisci i parametri che dovranno essere disponibili utilizzando questa macro. + + Seleziona il file partial view per la macro + + + Compilazione modelli in corso... + + Modelli generati + Impossibile generare i modelli + La generazione dei modelli non è andata a buon fine, consulta i log di Umbraco + - - + Aggiungi campo alternativo + Campo alternativo + Aggiungi valore predefinito + Valore predefinito + Campo alternativo + Valore predefinito + Codifica Scegli il campo Converte le interruzioni di linea - + Si, converti le interruzioni di linea + Campi Personalizzati - + Solo data + Formato e codifica + Formatta il valore in data, o in data e ora, secondo la cultura corrente - + Minuscolo + Modifica output Nessuno + Esempio di output - + Ricorsivo - - + Si, rendilo ricorsivo + Separatore Campi Standard Maiuscolo - + + - + Data e ora - Dettagli - Scarica xml DTD + Dettagli di traduzione + Scarica XML DTD Campi Includi le sottopagine - + + - + - + + Traduttore + Contenuti + Modelli di contenuto + Media Cache Browser Cestino Pacchetti creati @@ -853,10 +2081,13 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in Membri Gruppi di Membri Ruoli - Tipologia Membri + Tipi di membro Tipi di documento + Tipi di relazione Pacchetti Pacchetti + Partial Views + Macro Partial Views Installa dal repository Installa Runway Moduli Runway @@ -864,83 +2095,849 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in Scripts Fogli di stile Templates - Permessi Utente - Tipi di Utente + Logs Utenti - Contenuti + Impostazioni + Templating + Terze parti - - + + - + + + Accesso + Basandosi sui gruppi assegnati e sui nodi di partenza, l'utente ha accesso ai seguenti + nodi + + Assegna accessi Amministratore Campo Categoria + Utente creato il Cambia la tua password - + Cambia foto + Nuova password + Minimo %0% caratteri! + Dovrebbero esserci almeno %0% caratteri speciali qui. + + Conferma la nuova password + + Contenuto del canale + Crea un altro utente + Crea nuovi utenti per dar loro accesso a Umbraco. Quando un nuovo utente viene creato, + una nuova password da condividere con l'utente viene generata. + Campo Descrizione Disabilita l'utente Tipo di Documento Editor Campo Eccezione + Tentativi di accesso falliti + Vai al profilo dell'utente + Crea gruppi per assegnare gli accessi e i permessi + Invita un altro utente + + Lingua + Imposta la lingua che vedrai nei menu e nei dialoghi + Data dell'ultimo blocco + Ultimo login + Ultima modifica della password Login - + Nodo di inizio nella sezione Media + Limita la libreria multimediale a un nodo iniziale specifico + Nodi di inizio nella sezione Media + + Sezioni - Modifica la tua password + non ha ancora effettuato l'accesso + Vecchia password Password + Resetta password + Password cambiata - Password attuale - - + Password attuale + + + + Rimuovi foto + Permessi predefiniti + Permessi granulari + Imposta i permessi per nodi specifici + Profilo + Aggiungi sezioni per cui l'utente deve avere accesso + Seleziona gruppi di utenti + Nodo di partenza non selezionato + Nodi di partenza non selezionati + Limita l'albero dei contenuti a un nodo iniziale specifico + Nodi di inizio del contenuto + + Ultimo aggiornamento utente + + + + Gestione utenti Username - - + Gruppo di utenti + + + + Ciao e benvenuto su Umbraco! In solo 1 minuto sarai pronto a partire, dovrai + solamente impostare una password e aggiungere una foto profilo. + + + + Caricando una tua foto, gli altri utenti potranno riconoscerti facilmente. Fai + clic sul cerchio sopra per caricare la tua foto. + Autore + Modifica Il tuo profilo - La tua storia recente + + La sessione scade in + Invita utente Crea utente - Crea nuovi utenti e dai loro accesso ad Umbraco. Quando un nuovo utente viene creato viene generata una password che potrai condividere con l'utente. - Aggiungi gruppi per assegnare accessi e permessi + Invia invito Torna agli utenti - Gestione utenti + Invito per Umbraco + + + + + + + + + + + + +
      + + + + + +
      + +
      + +
      +
      + + + + + + +
      +
      +
      + + + + +
      + + + + +
      +

      + Ciao %0%, +

      +

      + Sei stato invitato nel Back Office di Umbraco da %1%. +

      +

      + Messaggio da %1%: +
      + %2% +

      + + + + + + +
      + + + + + + +
      + + Clicca questo link per accettare l'invito + +
      +
      +

      Se non puoi cliccare sul link, copia e incolla questo URL in una nuova finestra del tuo browser:

      + + + + +
      + + %3% + +
      +

      +
      +
      +


      +
      +
      + + ]]> +
      + Invita + Sto rinviando l'invito... + Cancella utente + Sei sicuro di voler cancellare questo account utente? + Tutti + Attivi + Disabilitati + Bloccati + Invitati + Inattivi + Nome (A-Z) + Nome (Z-A) + + + Ultimo login + Non sono stati aggiunti gruppi di utenti + Validazione + Valida come indirizzo email + Valida come numero + Valida come URL + ...oppure inserisci una validazione personalizzata + + Inserisci un errore di validazione personalizzato (opzionale) + Inserisci una regular expression + Inserisci un errore di validazione personalizzato (opzionale) Devi aggiungere almeno + Puoi avere solamente + Aggiungi fino a elementi + URL + URL selezionati + elementi selezionati + Data non valida + + + Email non valida + + + + Validazione personalizzata + %1% in più.]]> + %1% di troppo.]]> - - Digita per cercare... - Inserisci la tua email - Inserisci la tua password - Inserisci un nome... - Inserisci una email... + + + + + + + + + + + Gli errori personalizzati sono impostati a '%0%'. + + + Errori personalizzati impostati correttamente a '%0%'. + I MacroErrors sono impostati a '%0%'. + + + I MacroErrors sono ora impostati a '%0%'. + + + + + + + + + Il file seguente non esiste: '%0%'. + + '%0%' nel file di configurazione '%1%'.]]> + + + + + Sono stati trovati %0% problemi con lo schema del database + (Controlla i log per dettagli aggiuntivi) + + Sono stati trovati alcuni errori durante la validazione + dello schema del database per la versione corrente di Umbraco. + + + Errore di validazione del certificato SSL: '%0%' + + + + Errore durante il ping dell'URL %0% - '%1%' + Attualmente %0% stai visualizzando il sito web utilizzando lo schema + HTTPS. + + + + + + Non posso aggiornare l'impostazione 'Umbraco.Core.UseHttps' nel file + web.config. Errore: %0% + + + Abilita HTTPS + Imposta il valore di umbracoSSL a true nelle appSetting del file + web.config. + + + + Correggi + Non posso correggere un controllo con un valore di confronto pari a + 'ShouldNotEqual'. + + Non posso correggere un controllo con un valore di confronto pari a + 'ShouldEqual' con un valore fornito. + + + + + + + + + + + + + Tutte le cartelle hanno i permessi corretti impostati. + + + %0%.]]> + + %0%. Se non vengono scritte non è necessario intraprendere alcuna azione.]]> + Tutti i file hanno i permessi corretti impostati. + + + %0%.]]> + + %0%. Se non vengono scritti non è necessario intraprendere alcuna azione.]]> + + X-Frame-Options usato per controllare se un sito può essere inserito in un IFRAME da un altro è stato trovato.]]> + + X-Frame-Options usato per controllare se un sito può essere inserito in un IFRAME da un altro non è stato trovato.]]> + Imposta l'header nella configurazione + Aggiunge un valore alla sezione httpProtocol/customHeaders del + file web.config per prevenire che un sito possa essere inserito in un IFRAME da altri siti web. + + + + Non posso aggiornare il file web.config. Errore: %0% + + X-Content-Type-Options usato per proteggere dalle vulnerabilità per MIME sniffing è stato trovato.]]> + + X-Content-Type-Options usato per proteggere dalle vulnerabilità per MIME sniffing è stato trovato.]]> + + + + + + Strict-Transport-Security, conosciuto anche come l'header HSTS, è stato trovato.]]> + + Strict-Transport-Security non è stato trovato.]]> + Aggiunge l'header 'Strict-Transport-Security' con il valore + 'max-age=10886400' alla sezione httpProtocol/customHeaders del file web.config. Usa questa correzione solo se + avrai i tuoi domini in esecuzione con https per le prossime 18 settimane (minimo). + + + + X-XSS-Protection è stato trovato.]]> + + X-XSS-Protection non è stato trovato.]]> + Aggiunge l'header 'X-XSS-Protection' con il valore '1; + mode=block' alla sezione httpProtocol/customHeaders del file web.config. + + + + + + %0%.]]> + Non sono stati trovati header che rivelano informazioni riguardo alla + tecnologia utilizzata per il sito. + + + + + + Le impostazioni SMTP sono state inserite correttamente e il servizio + funziona come previsto. + + + + + %0%.]]> + + %0%.]]> + +

      I risultati dell'Health Check programmato di Umbraco del %0% alle %1% è il seguente:

      %2%]]>
      + Stato dell'Health Check di Umbraco: %0% + Controlla tutti i gruppi + Controlla gruppo + + L'health checker valuta varie aree del tuo sito per le impostazioni delle migliori pratiche, la configurazione, i potenziali problemi, ecc. Puoi facilmente risolvere i problemi premendo un pulsante. + Puoi aggiungere i tuoi health check personalizzati, guarda sulla documentazione per più informazioni riguardo i custom health checks.

      + ]]> +
      - - o clicca qui per scegliere i file - Trascina i tuoi file all'interno di quest'area + + Disabilita tracciamento degli URL + Abilita tracciamento degli URL + Cultura + URL originale + Reindirizzato a + Gestione Redirect URL + I seguenti URL reindirizzano a questo contenuto: + + + + Sei sicuro di voler eliminare il reindirizzamento da '%0%' a '%1%'? + Reindirizzamento URL rimosso. + Errore durante la rimozione del reindirizzamento URL. + + Sei sicuro di voler disabilitare il tracciamento degli URL? + + + + + + - - Contenuti - Info + + Nessun elemento del dizionario tra cui scegliere + + + %0% caratteri rimasti.]]> + %1% di troppo.]]> + + + Contenuto cestinato con Id: {0} relativo al contenuto principale originale con Id: {1} + + Media cestinato con Id: {0} relativo al media principale originale con Id: {1} + Impossibile ripristinare automaticamente questo elemento + Non esiste una posizione in cui questo elemento possa essere ripristinato + automaticamente. Puoi spostare l'elemento manualmente utilizzando l'albero sottostante. + + + + + Direzione + Da genitore a figlio + Bidirezionale + Genitore + Figlio + Numero + Relazioni + Creato + Commento + Nome + Nessuna relazione per questo tipo di relazione + Tipo di relazione + Relazioni + + + Guida introduttiva + Gestione Redirect URL + Contenuto + Benvenuto + Gestione Examine + Stato di pubblicazione + Models Builder + Health Check + Profilazione + Guida introduttiva + Installa Umbraco Forms + + + Indietro + Layout attivo: + Vai a + gruppo + passato + attenzone + fallito + suggerimento + Check passato + Check fallito + Apri la ricerca nel backoffice + Apri/chiudi l'aiuto del backoffice + Apri/chiudi le opzioni del tuo profilo + Imposta le Culture e gli Hostnames per %0% + Crea nuovo nodo sotto %0% + Imposta le restrizioni di accesso per %0% + Imposta i permessi per %0% + Modifica l'ordinamento per %0% + Crea un modello di contenuto basato su %0% + Apri il menu contestuale per + Lingua corrente + Cambia lingua in + Crea nuova cartella + Partial View + Partial View Macro + Membro + Tipo di dato + Cerca nella dashboard di reindirizzamento + Cerca nella sezione dei gruppi di utenti + Cerca tra gli utenti + Crea oggetto + Crea + Modifica + Nome + Aggiungi nuova riga + + Cerca nel backoffice di Umbraco + Cerca contenuti, media, ecc. nel backoffice. + + + Percorso: + Trovato in + Ha una traduzione + Traduzione mancante + Voci del dizionario + Seleziona una delle opzioni per modificare il nodo. + Esegui l'azione %0% sul nodo %1% + Aggiungi una descrizione per l'immagine + Cerca nell'albero dei contenuti + Numero massimo + + + Riferimenti + Questo tipo di dato non ha riferimenti. + Usato nei tipi di documento + Non ci sono riferimenti a tipi di documento. + Usato nei tipi di media + Non ci sono riferimenti a tipi di media. + Usato nei tipi di membro + Non ci sono riferimenti a tipi di membro. + Usato da + Usato nei documenti + Usato nei membri + Usato nei media + Elimina ricerca salvata + Livelli di log Seleziona tutto Deselezionare tutto + Ricerche salvate + Salva ricerca + Inserisci un nome descrittivo per la tua query di ricerca + Filtra la ricerca + Risultati totali + Timestamp + Livello + Macchina + Messaggio + Exception + + Ricerca con Google + Ricerca questo messaggio con Google + Ricerca con Bing + Ricerca questo messaggio con Bing + Ricerca su Our Umbraco + Ricerca questo messaggio sui forum e le documentazioni di + Our Umbraco + + Ricerca su Our Umbraco con Google + Ricerca sui forum di Our Umbraco con Google + Ricerca nel codice sorgente di Umbraco + Ricerca nel codice sorgente di Umbraco su GitHub + Ricerca tra i problemi di Umbraco + Ricerca tra i problemi di Umbraco su GitHub + Elimina questa ricerca + Trova log con Request ID + Trova log con Namespace + Trova log con Machine Name + Apri + Polling + Ogni 2 secondi + Ogni 5 secondi + Ogni 10 secondi + Ogni 20 secondi + Ogni 30 secondi + Polling ogni 2s + Polling ogni 5s + Polling ogni 10s + Polling ogni 20s + Polling ogni 30s + + + Copia %0% + %0% da %1% + Lista di %0% + Rimuovi tutti gli oggetti + Svuota appunti + + + + + + + Attendi + Aggiorna stato + Memory Cache + + + + Ricarica + Cache del Database + + La ricostruzione può metterci del tempo. + Usalo quando la ricarica della Memory Cache non è sufficiente e pensi che la cache del database non sia + stata generata correttamente, che indicherebbe un problema critico di Umbraco. + ]]> + + Ricostruisci + Interni + + non hai bisogno di usarlo. + ]]> + + Raccogli + Stato della Published Cache + Caches + + + Profilazione delle performance + + + Umbraco attualmente funziona in modalità debug. Ciò significa che puoi utilizzare il profiler delle prestazioni integrato per valutare le prestazioni durante il rendering delle pagine. +

      +

      + Se vuoi attivare il profiler per il rendering di una pagina specifica, aggiungi semplicemente umbDebug=true alla querystring quando richiedi la pagina. +

      +

      + Se vuoi che il profiler sia attivato per impostazione predefinita per tutti i rendering di pagina, puoi utilizzare l'interruttore qui sotto. + Verrà impostato un cookie nel tuo browser, che quindi attiverà automaticamente il profiler. + In altre parole, il profiler sarà attivo per impostazione predefinita solo nel tuo browser, non in quello di tutti gli altri. +

      + ]]> +
      + Attiva la profilazione per impostazione predefinita + Promemoria + + + Non dovresti mai lasciare che un sito di produzione venga eseguito in modalità debug. La modalità di debug viene disattivata impostando debug="false" nell'elemento <compilation /> nel file web.config. +

      + ]]> +
      + + + Umbraco attualmente non viene eseguito in modalità debug, quindi non è possibile utilizzare il profiler integrato. Questo è come dovrebbe essere per un sito produttivo. +

      +

      + La modalità di debug viene attivata impostando debug="true" nell'elemento <compilation /> in web.config. +

      + ]]> +
      + + + Ore di videoallenamenti su Umbraco sono a solo un click da te + + Vuoi padroneggiare Umbraco? Dedica un paio di minuti all'apprendimento di alcune best practice guardando uno di questi video sull'utilizzo di Umbraco. Visita umbraco.tv per altri video su Umbraco

      + ]]> +
      + Per iniziare + + + Inizia da qui! + + + + + nella documentazione di Our Umbraco + ]]> + + + Community Forum + ]]> + + + video tutorial (alcuni sono gratuiti, altri richiedono un abbonamento) + ]]> + + + strumenti per aumentare la produttività e il supporto commerciale + ]]> + + + certificazione + ]]> + + + + Benvenuto nell'amichevole CMS + + + + + Umbraco Forms + Crea moduli utilizzando un'interfaccia drag and drop intuitiva. Da semplici moduli di + contatto che inviano e-mail a questionari avanzati che si integrano con i sistemi CRM. I tuoi clienti lo + adoreranno! + + + + Scegli tipo di elemento + Allega un tipo di elemento delle impostazioni + Seleziona vista + Seleziona foglio di stile + Scegli miniatura + Crea nuovo tipo di elemento + Foglio di stile personalizzato + Aggiungi foglio di stile + Aspetto dell'editor + Modelli di dati + Aspetto del catalogo + Colore di sfondo + Colore dell'icona + Modello del contenuto + Etichetta + Vista personalizzata + Mostra la descrizione della vista personalizzata + + + Modello di impostazioni + Dimensione dell'editor di sovrapposizione + Aggiungi vista personalizzata + Aggiungi impostazioni + Sovrascrivi modello di etichetta + + %0%?]]> + + %0%?]]> + + + + Miniatura + Aggiungi miniatura + Crea vuota + Appunti + Impostazioni + Avanzate + Forza nascondi editor di contenuti + Hai fatto delle modifiche a questo contenuto. Sei sicuro di volerle scartare? + Scartare la creazione? + + Errore! + + + Aggiungi contenuto + Aggiungi %0% + + + + + Cosa sono i modelli di contenuto? + I modelli di contenuto sono contenuti predefiniti che possono essere selezionati + durante la creazione di un nuovo nodo di contenuto. + + Come creo un modello di contenuto? + + Ci sono due modi per creare un modello di contenuto:

      +
        +
      • Fare clic con il pulsante destro del mouse su un nodo di contenuto e selezionare "Crea modello di contenuto" per creare un nuovo modello di contenuto.
      • +
      • Fare clic con il pulsante destro del mouse sull'albero dei modelli di contenuto nella sezione Impostazioni e selezionare il tipo di documento per il quale si desidera creare un modello di contenuto.
      • +
      +

      Una volta specificato un nome, gli editors potranno cominciare a usare il tipo di contenuto come base per la nuova pagina.

      + ]]> +
      + Come gestisco i modelli di contenuto? + Puoi modificare ed eliminare i modelli di contenuto dall'albero "Modelli di + contenuto" nella sezione Impostazioni. Espandere il tipo di documento su cui si basa il modello di contenuto e + fare clic su di esso per modificarlo o eliminarlo. + + + + Chiudi + Chiudi anteprima + Anteprima sito web + + Aprire l'anteprima del sito web? + + + Anteprima dell'ultima versione + Visualizza versione pubblicata + Vuoi vedere la versione pubblicata? + + + Visualizza versione pubblicata + + + + oggetto trovato + oggetti trovati diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml b/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml index b23fd0b8b169..ec64aceb3b6e 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml @@ -103,7 +103,7 @@ Bewerk huidige domeinen Overerven - Cultuur @@ -115,9 +115,9 @@ Tonen voor Inhoud verwijderd Inhoud gedepubliceerd - Inhoud gedepubliceerd voor talen: %0% + Inhoud gedepubliceerd voor talen: %0% Inhoud gepubliceerd - Inhoud gepubliceerd voor talen: %0% + Inhoud gepubliceerd voor talen: %0% Inhoud bewaard Inhoud bewaard voor talen: %0% Inhoud verplaatst @@ -225,9 +225,15 @@ Dit media item heeft geen link Inhoud kan niet worden toegevoegd aan dit item Eigenschappen - Dit document is gepubliceerd maar niet zichtbaar omdat de bovenliggende pagina '%0%' niet gepubliceerd is - Deze cultuur is gepubliceerd maar is niet zichtbaar omdat het niet gepubliceerd is op de bovenliggende pagina '%0%' - Dit document is gepubliceerd, maar het staat niet in de cache (interne serverfout) + Dit document is gepubliceerd maar niet zichtbaar omdat de bovenliggende pagina '%0%' + niet gepubliceerd is + + Deze cultuur is gepubliceerd maar is niet zichtbaar omdat het niet + gepubliceerd is op de bovenliggende pagina '%0%' + + Dit document is gepubliceerd, maar het staat niet in de cache (interne + serverfout) + Kan de URL niet ophalen Dit document is gepubliceerd maar de URL conflicteert met %0% Dit document is gepubliceerd maar de URL kan niet worden gerouteerd @@ -235,14 +241,18 @@ Gepubliceerd Gepubliceerd (hangende wijzigingen) Publicatiestatus - %0% en alle onderliggende content items en maak daarmee de inhoud openbaar.]]> - + + %0% en alle onderliggende content items en maak daarmee de inhoud openbaar.]]> + + Publiceren op Depubliceren op Verwijderdatum Datum instellen De sorteervolgorde is gewijzigd - Om nodes te sorteren, sleep de nodes of klik op één van de kolomtitels. Je kan meerdere nodes tegelijk selecteren door de "shift"- of "control"knop in te drukken tijdens het selecteren. + Om nodes te sorteren, sleep de nodes of klik op één van de kolomtitels. Je kan meerdere nodes + tegelijk selecteren door de "shift"- of "control"knop in te drukken tijdens het selecteren. + Statistieken Titel (optioneel) Alternatieve tekst (optioneel) @@ -261,26 +271,37 @@ Subitems Doel Dit betekend de volgende tijd op de server: - Wat houd dit in?]]> + + Wat houd dit in?]]> Ben je er zeker van dat je dit item wilt verwijderen? Ben je zeker dat je alle items wilt verwijderen? - Eigenschap %0% gebruikt editor %1% welke niet wordt ondersteund door Nested Content. + Eigenschap %0% gebruikt editor %1% welke niet wordt ondersteund door + Nested Content. + Er zijn geen content types geconfigureerd voor deze eigenschap. Element type toevoegen Selecteer een element type - Selecteer de groep waarvan je de eigenschappen wil tonen. Indien je niets selecteert, wordt de eerste groep van het elementtype gebruikt. - Voer een angular expressie in om te evalueren tegen de naam van elk item. Gebruik + Selecteer de groep waarvan je de eigenschappen wil tonen. Indien je niets + selecteert, wordt de eerste groep van het elementtype gebruikt. + + Voer een angular expressie in om te evalueren tegen de naam van elk + item. Gebruik + om de itemindex weer te geven Voeg nog een tekstvak toe Verwijder dit tekstvak Content root Inclusief niet-gepubliceerde inhoudsitems. - Deze waarde is verborgen. Indien u toegang nodig heeft om deze waarde te bekijken, neem dan contact op met uw websitebeheerder. + Deze waarde is verborgen. Indien u toegang nodig heeft om deze waarde te bekijken, + neem dan contact op met uw websitebeheerder. + Deze waarde is verborgen Welke talen wil je publiceren? Welke talen wil je ter goedkeuring verzenden? Welke talen wil je plannen? - Selecteer de talen om te depubliceren. Een verplichte taal depubliceren zal alle talen depubliceren. + Selecteer de talen om te depubliceren. Een verplichte taal depubliceren zal alle + talen depubliceren. + Alle nieuwe varianten worden opgeslagen. Welke varianten wil je publiceren? Kies welke varianten u wilt opslaan. @@ -289,19 +310,22 @@ Klaar om te publiceren? Klaar om op te slaan? Ter goedkeuring verzenden - Selecteer de datum en tijd om het content item te publiceren en/of depubliceren. + Selecteer de datum en tijd om het content item te publiceren en/of depubliceren. + Maak nieuw Plakken vanaf het klembord Dit item is in de prullenbak - Nieuw Inhoudssjabloon aanmaken voor '%0%' + %0%]]> Leeg Selecteer een Inhoudssjabloon Inhoudssjabloon aangemaakt Inhoudssjabloon is aangemaakt voor '%0%' Er bestaat al een Inhoudssjabloon met dezelfde naam - Een inhoudssjabloon is voorgedefinieerde inhoud die een editor kan selecteren om te gebruiken als basis voor het maken van nieuwe inhoud + Een inhoudssjabloon is voorgedefinieerde inhoud die een editor kan selecteren om + te gebruiken als basis voor het maken van nieuwe inhoud + Klik om te uploaden @@ -326,14 +350,22 @@ Selecteer een documenttype waarvoor je een Inhoudssjabloon wil maken Voer een mapnaam in Kies een type en een titel - "Documenttypes".]]> - Documenttypes in de sectie Instellingen.]]> - De geselecteerde pagina in de boomstructuur laat geen nieuwe onderliggende paginas toe. + + "Documenttypes".]]> + + Documenttypes in de sectie Instellingen.]]> + De geselecteerde pagina in de boomstructuur laat geen nieuwe + onderliggende paginas toe. + Rechten aanpassen voor dit documenttype Nieuw documenttype aanmaken - Documenttypes in de sectie Instellingen, de optie Toestaan op root-niveau onder Rechten.]]> - "Mediatypes".]]> - De geselecteerde media in de boomstructuur laat niet toe dat er onderliggende media aangemaakt wordt. + + Documenttypes in de sectie Instellingen, de optie Toestaan op root-niveau onder Rechten.]]> + + "Mediatypes".]]> + De geselecteerde media in de boomstructuur laat niet toe dat er + onderliggende media aangemaakt wordt. + Rechten aanpassen voor dit mediatype Documenttype zonder sjabloon Nieuwe map @@ -350,7 +382,8 @@ Open je website - Verbergen - Als Umbraco niet geopend wordt dan moet je mogelijk popups toestaan voor deze site. + Als Umbraco niet geopend wordt dan moet je mogelijk popups toestaan voor deze site. + is geopend in een nieuw venster Herstarten Bezoek @@ -360,11 +393,17 @@ Blijf op deze pagina Negeer wijzigingen Wijzigingen niet opgeslagen - Weet je zeker dat deze pagina wilt verlaten? Er zijn onopgeslagen wijzigingen + Weet je zeker dat deze pagina wilt verlaten? Er zijn onopgeslagen wijzigingen + Publiceren maakt de geselecteerde items zichtbaar op de site. - Depubliceren zal de geselecteerde items en alle onderliggende items verwijderen van de site. - Depubliceren zal deze pagina en alle onderliggende pagina's verwijderen van de site. - Wijzigingen niet opgeslagen. Aanpassingen aan het Documenttype zullen de wijzigingen ongedaan maken. + Depubliceren zal de geselecteerde items en alle onderliggende items + verwijderen van de site. + + Depubliceren zal deze pagina en alle onderliggende pagina's verwijderen van de site. + + Wijzigingen niet opgeslagen. Aanpassingen aan het Documenttype zullen de + wijzigingen ongedaan maken. + Done @@ -413,7 +452,9 @@ Klik om een Macro toe te voegen Tabel invoegen Dit zal de taal verwijderen - De cultuur veranderen voor een taal kan een langdurige operatie zijn en zal ertoe leiden dat de inhoudscache en indexen opnieuw worden opgebouwd + De cultuur veranderen voor een taal kan een langdurige operatie zijn en zal ertoe + leiden dat de inhoudscache en indexen opnieuw worden opgebouwd + Laatst aangepast op Link Interne link: @@ -425,16 +466,23 @@ Rechten instellen voor Rechten instellen voor %0% voor gebruikersgroepf %1% Selecteer de gebruikersgroepen waarvoor u de rechten wilt instellen - De items worden nu uit de prullenbak verwijderd. Sluit dit venster niet terwijl de actie nog niet voltooid is. + De items worden nu uit de prullenbak verwijderd. Sluit dit venster niet terwijl de + actie nog niet voltooid is. + De prullenbak is nu leeg. Als items worden verwijderd uit de prullenbak, zijn ze voorgoed verwijderd. - regexlib.com ondervindt momenteel problemen waarover we geen controle hebben. Onze excuses voor het ongemak.]]> - Zoek naar een reguliere expressie om validatie aan een formulierveld toe te voegen. Voorbeeld: 'email', 'postcode', 'URL'. + + regexlib.com ondervindt momenteel problemen waarover we geen controle hebben. Onze excuses voor het ongemak.]]> + Zoek naar een reguliere expressie om validatie aan een formulierveld toe te voegen. + Voorbeeld: 'email', 'postcode', 'URL'. + Verwijder Macro Verplicht veld Site is opnieuw geïndexeerd De site is opnieuw gepubliceerd - De cache zal worden vernieuwd. Alle gepubliceerde inhoud zal worden bijgewerkt, terwijl ongepubliceerde inhoud ongepubliceerd zal blijven. + De cache zal worden vernieuwd. Alle gepubliceerde inhoud zal worden bijgewerkt, + terwijl ongepubliceerde inhoud ongepubliceerd zal blijven. + Aantal kolommen Aantal regels Klik op de afbeelding voor volledige grootte @@ -476,7 +524,9 @@ Selecteer editor Selecteer configuratie Selecteer fragment - Dit zal de node en al zijn talen verwijderen. Als je slechts één taal wil verwijderen, moet je de node in die taal depubliceren. + Dit zal de node en al zijn talen verwijderen. Als je slechts één taal wil + verwijderen, moet je de node in die taal depubliceren. + %0% verwijderen.]]> %0% verwijderen van de %1% groep]]> Ja, verwijderen @@ -496,7 +546,9 @@ Ingestelde Zoekers - Toont eigenschappen en hulpmiddelen voor elke geconfigureerde Zoeker (bijv. zoals een multi-indexzoeker) + Toont eigenschappen en hulpmiddelen voor elke geconfigureerde Zoeker + (bijv. zoals een multi-indexzoeker) + Veldwaarden Gezondheidsstatus De gezondheidsstatus van de index en of het kan gelezen worden @@ -504,7 +556,9 @@ Index info De eigenschappen oplijsten van de index Beheer de indexen van Examine - Bekijk de details van elke index en gebruik hulpmiddelen voor het beheer er van + Bekijk de details van elke index en gebruik hulpmiddelen voor het beheer er + van + Index opnieuw bouwen @@ -518,7 +572,9 @@ Hulpmiddelen om de index te beheren velden De index kan niet gelezen worden en moet opnieuw worden gebouwd - Het proces duurt langer dan verwacht, controleer het Umbraco logboek om te kijken of er geen fouten waren tijdens deze operatie + Het proces duurt langer dan verwacht, controleer het Umbraco logboek om te kijken + of er geen fouten waren tijdens deze operatie + Deze index kan niet opnieuw worden opgebouwd want het heeft geen toegewezen IIndexPopulator @@ -570,16 +626,25 @@ Selecteer een map om te verplaatsen naar in de boomstructuur hieronder werd eronder verplaatst - %0% te verwijderen zullen alle eigenschappen en de data verwijderd worden van de volgende items:]]> - Ik begrijp dat deze actie alle eigenschappen en data zal verwijderen die gebaseerd is op dit datatype. + + %0% te verwijderen zullen alle eigenschappen en de data verwijderd worden van de volgende items:]]> + Ik begrijp dat deze actie alle eigenschappen en data zal verwijderen die + gebaseerd is op dit datatype. + - Je data is opgeslagen, maar voordat je deze pagina kunt publiceren moet je eerst aan paar problemen oplossen: - Veranderen van het wachtwoord wordt door de huidige Membership Provider niet ondersteund (EnablePasswordRetrieval moet op true staan) + Je data is opgeslagen, maar voordat je deze pagina kunt publiceren moet je eerst + aan paar problemen oplossen: + + Veranderen van het wachtwoord wordt door de huidige Membership Provider + niet ondersteund (EnablePasswordRetrieval moet op true staan) + %0% bestaat al Er zijn fouten geconstateerd: Er zijn fouten geconstateerd: - Het wachtwoord moet minstens %0% tekens lang zijn en moet minstens %1% cijfers bevatten + Het wachtwoord moet minstens %0% tekens lang zijn en moet minstens %1% cijfers + bevatten + %0% moet een geheel getal zijn %0% op tab %1% is een verplicht veld %0% is een verplicht veld @@ -589,13 +654,19 @@ Een error ontvangen van de server Het opgegeven bestandstype is niet toegestaan ​​door de beheerder - OPMERKING! Ondanks dat CodeMiror is ingeschakeld, is het uitgeschakeld in Internet Explorer omdat het niet stabiel genoeg is. - Zowel de alias als de naam van het nieuwe eigenschappentype moeten worden ingevuld! + OPMERKING! Ondanks dat CodeMiror is ingeschakeld, is het uitgeschakeld in Internet + Explorer omdat het niet stabiel genoeg is. + + Zowel de alias als de naam van het nieuwe eigenschappentype moeten + worden ingevuld! + Er is een probleem met de lees/schrijfrechten op een bestand of map Error bij het laden van Partial View script (file: %0%) Vul een titel in Selecteer een type - U wilt een afbeelding groter maken dan de originele afmetingen. Weet je zeker dat je wilt doorgaan? + U wilt een afbeelding groter maken dan de originele afmetingen. Weet je + zeker dat je wilt doorgaan? + Start node is verwijderd, neem contact op met uw systeembeheerder Markeer de inhoud voordat u de stijl aanpast Geen actieve stijlen beschikbaar @@ -761,7 +832,6 @@ Blauw - Tabblad toevoegen Groep toevoegen Eigenschap toevoegen Editor toevoegen @@ -797,38 +867,63 @@ De installer kan geen connectie met de database maken. Je database is gevonden en is geïdentificeerd als - Database configuratie - installeren om de Umbraco %0% database te installeren]]> - Volgende om door te gaan.]]> - Gelieve contact op te nemen met je ISP indien nodig. Wanneer je installeert op een lokale computer of server, dan heb je waarschijnlijk informatie nodig van je systeembeheerder.]]> - Klik de upgrade knop om je database te upgraden naar Umbraco %0%

      Maak je geen zorgen - er zal geen inhoud worden gewist en alles blijft gewoon werken!

      ]]>
      - Klik Volgende om verder te gaan.]]> - volgende om door te gaan]]> - Het wachtwoord van de default gebruiker dient veranderd te worden!]]> - De default gebruiker is geblokkeerd of heeft geen toegang tot Umbraco!

      Geen verdere actie noodzakelijk. Klik Volgende om verder te gaan.]]> - Het wachtwoord van de default gebruiker is sinds installatie met succes veranderd.

      Geen verdere actie noodzakelijk. Klik Volgende om verder te gaan.]]> + Database configuratie + + installeren om de Umbraco %0% database te installeren]]> + + Volgende om door te gaan.]]> + + Gelieve contact op te nemen met je ISP indien nodig. Wanneer je installeert op een lokale computer of server, dan heb je waarschijnlijk informatie nodig van je systeembeheerder.]]> + + Klik de upgrade knop om je database te upgraden naar Umbraco %0%

      Maak je geen zorgen - er zal geen inhoud worden gewist en alles blijft gewoon werken!

      ]]>
      + + Klik Volgende om verder te gaan.]]> + + volgende om door te gaan]]> + + Het wachtwoord van de default gebruiker dient veranderd te worden!]]> + + De default gebruiker is geblokkeerd of heeft geen toegang tot Umbraco!

      Geen verdere actie noodzakelijk. Klik Volgende om verder te gaan.]]> + + Het wachtwoord van de default gebruiker is sinds installatie met succes veranderd.

      Geen verdere actie noodzakelijk. Klik Volgende om verder te gaan.]]> Het wachtwoord is veranderd! Neem een jumpstart en bekijk onze introductie videos Nog niet geïnstalleerd. Betreffende bestanden en mappen - Meer informatie over het instellen van machtigingen voor Umbraco vind je hier - Je dient ASP.NET 'modify' machtiging te geven voor de volgende bestanden/mappen - Je machtigingen zijn bijna perfect!

      Je kunt Umbraco zonder problemen starten, maar je kunt nog geen packages installeren om volledig van Umbraco te profiteren.]]>
      + Meer informatie over het instellen van machtigingen voor Umbraco + vind je hier + + Je dient ASP.NET 'modify' machtiging te geven voor de volgende + bestanden/mappen + + + Je machtigingen zijn bijna perfect!

      Je kunt Umbraco zonder problemen starten, maar je kunt nog geen packages installeren om volledig van Umbraco te profiteren.]]>
      Hoe op te lossen Klik hier om de tekst versie te lezen - video tutorial over het instellen van machtigingen voor Umbraco, of lees de tekst versie.]]> - Je machtigingen zijn misschien incorrect!

      Je kunt Umbraco probleemloos starten, maar je kunt nog geen mappen aanmaken of packages installeren om zo volledig van Umbraco te profiteren.]]>
      - Je machtigingen zijn nog niet gereed gemaakt voor Umbraco!

      Om Umbraco te starten zul je je machtigingen moeten aanpassen.]]>
      - Je machtigingen zijn perfect!

      Je bent nu klaar om Umbraco te starten en om packages te installeren!]]>
      + + video tutorial over het instellen van machtigingen voor Umbraco, of lees de tekst versie.]]> + + Je machtigingen zijn misschien incorrect!

      Je kunt Umbraco probleemloos starten, maar je kunt nog geen mappen aanmaken of packages installeren om zo volledig van Umbraco te profiteren.]]>
      + + Je machtigingen zijn nog niet gereed gemaakt voor Umbraco!

      Om Umbraco te starten zul je je machtigingen moeten aanpassen.]]>
      + + Je machtigingen zijn perfect!

      Je bent nu klaar om Umbraco te starten en om packages te installeren!]]>
      Map probleem wordt opgelost - Volg deze link voor meer informatie over problemen met ASP.NET en het aanmaken van mappen + Volg deze link voor meer informatie over problemen met ASP.NET en + het aanmaken van mappen + Machtigingen worden aangepast - Umbraco heeft write/modify toegang nodig op bepaalde mappen om bestanden zoals plaatjes en PDF's op te slaan. Het slaat ook tijdelijke data (ook bekend als 'de cache') op om de snelheid van je website te verbeteren. + Umbraco heeft write/modify toegang nodig op bepaalde mappen om bestanden zoals plaatjes + en PDF's op te slaan. Het slaat ook tijdelijke data (ook bekend als 'de cache') op om de snelheid van je website + te verbeteren. + Ik wil met een lege website beginnen - leer hoe). Je kunt er later alsnog voor kiezen om Runway te installeren. Ga dan naar de Ontwikkelaar sectie en kies Packages.]]> + + leer hoe). Je kunt er later alsnog voor kiezen om Runway te installeren. Ga dan naar de Ontwikkelaar sectie en kies Packages.]]> Je hebt zojuist een blanco Umbraco platform geinstalleerd. Wat wil je nu doen? Runway is geinstalleerd - Dit is onze lijst van aanbevolen modules. Vink de modules die je wilt installeren, of bekijk de volledige lijst modules]]> + + Dit is onze lijst van aanbevolen modules. Vink de modules die je wilt installeren, of bekijk de volledige lijst modules]]> Alleen aanbevolen voor gevorderde gebruikers Ik wil met een eenvoudige website beginnen "Runway" is een eenvoudige website die je van enkele elementaire documenttypes en templates voorziet. De installer kan Runway automatisch voor je opzetten, maar je kunt het gemakkelijk aanpassen, uitbreiden of verwijderen. Het is niet vereist en je kunt Umbraco prima zonder Runway gebruiken. @@ -842,16 +937,21 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Stap 4/5: Umbraco beveiliging controleren Stap 5/5: Umbraco is klaar Bedankt dat je voor Umbraco hebt gekozen - Browse je nieuwe site Je hebt Runway geinstalleerd, dus kijk eens hoe je nieuwe site eruit ziet.]]> - Meer hulp en informatie Vind hulp in onze bekroonde community, blader door de documentatie of bekijk enkele gratis videos over het bouwen van een eenvoudige site, het gebruiken van packages en een overzicht van Umbraco terminologie]]> + + Browse je nieuwe site Je hebt Runway geinstalleerd, dus kijk eens hoe je nieuwe site eruit ziet.]]> + + Meer hulp en informatie Vind hulp in onze bekroonde community, blader door de documentatie of bekijk enkele gratis videos over het bouwen van een eenvoudige site, het gebruiken van packages en een overzicht van Umbraco terminologie]]> Umbraco %0% is geïnstalleerd en klaar voor gebruik. - meteen beginnen door de "Launch Umbraco" knop hieronder te klikken.
      Als je een beginnende Umbraco gebruiker bent, dan kun je you can find veel informatie op onze "getting started" pagina's vinden.]]>
      - Launch Umbraco Om je website te beheren open je simpelweg de Umbraco backoffice en begin je inhoud toe te voegen, templates en stylesheets aan te passen of nieuwe functionaliteit toe te voegen]]> + + meteen beginnen door de "Launch Umbraco" knop hieronder te klikken.
      Als je een beginnende Umbraco gebruiker bent, dan kun je you can find veel informatie op onze "getting started" pagina's vinden.]]>
      + + Launch Umbraco Om je website te beheren open je simpelweg de Umbraco backoffice en begin je inhoud toe te voegen, templates en stylesheets aan te passen of nieuwe functionaliteit toe te voegen]]> Verbinding met de database mislukt. Umbraco versie 3 Umbraco versie 4 Bekijken - Umbraco %0% voor een nieuwe installatie of een upgrade van versie 3.0.

      Druk op "volgende" om de wizard te starten.]]>
      + + Umbraco %0% voor een nieuwe installatie of een upgrade van versie 3.0.

      Druk op "volgende" om de wizard te starten.]]>
      Cultuurcode @@ -872,10 +972,15 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je log hieronder in Inloggen met Sessie is verlopen - © 2001 - %0%
      umbraco.com

      ]]>
      + + © 2001 - %0%
      umbraco.com

      ]]>
      Wachtwoord vergeten? - Er zal een e-mail worden gestuurd naar het e-mailadres van jouw account. Hierin staat een link om je wachtwoord te resetten - Een e-mail met daarin de wachtwoord reset uitleg zal worden gestuurd als het e-mailadres in onze database voorkomt. + Er zal een e-mail worden gestuurd naar het e-mailadres van jouw account. + Hierin staat een link om je wachtwoord te resetten + + Een e-mail met daarin de wachtwoord reset uitleg zal worden gestuurd + als het e-mailadres in onze database voorkomt. + Wachtwoord tonen Wacthwoord verbergen Terug naar loginformulier @@ -883,7 +988,8 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Je wachtwoord is aangepast De link die je hebt aangeklikt is niet (meer) geldig. Umbraco: Wachtwoord Reset - De gebruikersnaam om in te loggen bij jouw Umbraco omgeving is: %0%

      Klik hier om je wachtwoord te resetten of knip/plak deze URL in je browser:

      %1%

      ]]>
      + + De gebruikersnaam om in te loggen bij jouw Umbraco omgeving is: %0%

      Klik hier om je wachtwoord te resetten of knip/plak deze URL in je browser:

      %1%

      ]]>
      Dashboard @@ -897,8 +1003,12 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je %0% is verplaatst naar %1% Verplaats naar is geselecteerd als root van je nieuwe pagina, klik hieronder op 'ok'. - Nog geen node geselecteerd, selecteer eerst een node in bovenstaade lijst voordat je op 'volgende' klikt - De huidige node is niet toegestaan onder de geselecteerde node vanwege het node type + Nog geen node geselecteerd, selecteer eerst een node in bovenstaade lijst voordat je op + 'volgende' klikt + + De huidige node is niet toegestaan onder de geselecteerde node vanwege het node + type + De huidige node kan niet naar een van zijn subpagina’s worden verplaatst. De huidige node kan niet worden gebruikt op root-niveau Deze actie is niet toegestaan omdat je onvoldoende rechten hebt op één of meer subitems. @@ -922,7 +1032,7 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je ]]>
      De volgende talen zijn gewijzigd %0% - Hi %0%

      + Hi %0%

      Dit is een geautomatiseerde mail om u op de hoogte te brengen dat de taak '%1%' is uitgevoerd op pagina '%2%' @@ -960,7 +1070,9 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Acties Aangemaakt Package aanmaken - Kies een package op je computer door op "Bladeren" te klikken en de package te selecteren. Umbraco packages hebben meestal ".umb" of ".zip" als extensie. + Kies een package op je computer door op "Bladeren" te klikken en de package te + selecteren. Umbraco packages hebben meestal ".umb" of ".zip" als extensie. + Dit zal de package verwijderen Inclusief alle onderliggende nodes Geïnstalleerd @@ -968,7 +1080,8 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Deze package heeft geen instellingen Er zijn nog geen packages aangemaakt Er zijn geen packages geïnstalleerd - 'Packages' rechtsboven in je scherm.]]> + + 'Packages' rechtsboven in je scherm.]]> Package Inhoud Licentie Zoeken naar packages @@ -988,7 +1101,10 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Downloads Likes Compatibiliteit - Deze package is compatibel met de volgende versies van Umbraco, zoals gerapporteerd door de communityleden. Volledige compatibiliteit kan niet worden gegarandeerd voor versies die voor minder dan 100% worden gerapporteerd + Deze package is compatibel met de volgende versies van Umbraco, zoals + gerapporteerd door de communityleden. Volledige compatibiliteit kan niet worden gegarandeerd voor versies die voor + minder dan 100% worden gerapporteerd + Externe bronnen Auteur Documentatie @@ -1013,31 +1129,43 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Plakken met alle opmaak (Niet aanbevolen) - De tekst die je probeert te plakken bevat speciale tekens en/of opmaak. Dit kan veroorzaakt worden doordat de tekst vanuit Microsoft Word is gekopieerd. Umbraco kan deze speciale tekens en formattering automatisch verwijderen zodat de geplakte tekst geschikt is voor het web. + De tekst die je probeert te plakken bevat speciale tekens en/of opmaak. Dit kan + veroorzaakt worden doordat de tekst vanuit Microsoft Word is gekopieerd. Umbraco kan deze speciale tekens en + formattering automatisch verwijderen zodat de geplakte tekst geschikt is voor het web. + Plakken als ruwe tekst en alle opmaak verwijderen Plakken, en verwijder de opmaak (aanbevolen) Groepsgebaseerde beveiliging Als je toegang wilt verlenen aan alle leden van specifieke ledengroepen - Je moet een ledengroep maken voordat je op groep gebaseerde authenticatie kunt gebruiken + Je moet een ledengroep maken voordat je op groep gebaseerde authenticatie kunt + gebruiken + Foutpagina - Gebruikt om te tonen als een gebruiker is ingelogd, maar geen rechten heeft om de pagina te bekijken + Gebruikt om te tonen als een gebruiker is ingelogd, maar geen rechten heeft om de + pagina te bekijken + %0% beveiligen?]]> %0% is nu beveiligd]]> %0%]]> Login Pagina Kies de pagina met het login-formulier Beveiliging verwijderen - %0% wilt verwijderen?]]> + + %0% wilt verwijderen?]]> Kies de pagina's die het login-formulier en de error-berichten bevatten - %0%]]> - %0%]]> + + %0%]]> + + %0%]]> Specifieke bescherming voor leden Als je toegang wilt verlenen aan bepaalde leden - Onvoldoende gebruikersmachtigingen om alle onderliggende documenten te publiceren + Onvoldoende gebruikersmachtigingen om alle onderliggende documenten te + publiceren + @@ -1057,8 +1185,11 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je - - Validatie mislukt voor de vereiste taal '%0%'. Deze taal werd opgeslagen maar is niet gepubliceerd. + + + Validatie mislukt voor de vereiste taal '%0%'. Deze + taal werd opgeslagen maar is niet gepubliceerd. + Publicatie in uitvoering - even geduld... %0% van %1% pagina’s zijn gepubliceerd... %0% is gepubliceerd @@ -1073,13 +1204,21 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Je kan alleen items van de volgende type(s) selecteren: %0% - Je hebt een content-item geselecteerd dat op dit ogenblik verwijderd of in the prullenbak is - Je hebt content-items geselecteerd die op dit ogenblik verwijderd of in the prullenbak zijn + Je hebt een content-item geselecteerd dat op dit ogenblik verwijderd of in the + prullenbak is + + Je hebt content-items geselecteerd die op dit ogenblik verwijderd of in the + prullenbak zijn + Verwijderd item - Je hebt een media-item geselecteerd dat op dit ogenblik verwijderd of in the prullenbak is - Je hebt media-items geselecteerd die op dit ogenblik verwijderd of in the prullenbak zijn + Je hebt een media-item geselecteerd dat op dit ogenblik verwijderd of in the + prullenbak is + + Je hebt media-items geselecteerd die op dit ogenblik verwijderd of in the prullenbak + zijn + Weggegooid @@ -1102,9 +1241,12 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Aangemaakt Selecteer een versie om te vergelijken met de huidige versie Huidige versie - Rode tekst wordt niet getoond in de geselecteerde versie, groen betekent toegevoegd]]> + + Rode tekst wordt niet getoond in de geselecteerde versie, groen betekent toegevoegd]]> Document is teruggezet - Hiermee wordt de geselecteerde versie als html getoond, als u de verschillen tussen de twee versies tegelijk wilt zien, gebruik dan de diff view + Hiermee wordt de geselecteerde versie als html getoond, als u de verschillen tussen de twee + versies tegelijk wilt zien, gebruik dan de diff view + Terugzetten naar Selecteer versie Bekijk @@ -1130,7 +1272,10 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Standaard template - Om een bestaand documenttype te importeren, zoek het betreffende “.udt” bestand door op browse en import te klikken. (Je ziet een bevestigingspagina voordat de import start. Als het documenttype al bestaat dan wordt het bijgewerkt.) + Om een bestaand documenttype te importeren, zoek het betreffende “.udt” bestand + door op browse en import te klikken. (Je ziet een bevestigingspagina voordat de import start. Als het documenttype + al bestaat dan wordt het bijgewerkt.) + Nieuwe tabtitel Node type Type @@ -1141,7 +1286,9 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Tabs Basis inhoudstype ingeschakeld Dit inhoudstype gebruikt - Geen eigenschappen gedefinieerd op dit tabblad. Klik op de link "voeg een nieuwe eigenschap" aan de bovenkant om een ​​nieuwe eigenschap te creëren. + Geen eigenschappen gedefinieerd op dit tabblad. Klik op de link "voeg een + nieuwe eigenschap" aan de bovenkant om een ​​nieuwe eigenschap te creëren. + Maak een bijpassende sjabloon Icoon toevoegen @@ -1149,17 +1296,22 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Sorteer volgorde Aanmaakdatum Sorteren gereed. - Sleep de pagina's omhoog of omlaag om de volgorde te veranderen. Of klik op de kolomkop om alle pagina's daarop te sorteren. + Sleep de pagina's omhoog of omlaag om de volgorde te veranderen. Of klik op de kolomkop om + alle pagina's daarop te sorteren. + Dit item heeft geen subitems om te sorteren Validatie - Validatiefouten moeten worden opgelost voor dit item kan worden opgeslagen + Validatiefouten moeten worden opgelost voor dit item kan worden opgeslagen + Mislukt Opgeslagen - Opgeslagen. Gelieve uw browser te herladen om de aanpassingen te zien - Wegens onvoldoende rechten kon deze handeling kon niet worden uitgevoerd + Opgeslagen. Gelieve uw browser te herladen om de aanpassingen te zien + + Wegens onvoldoende rechten kon deze handeling kon niet worden uitgevoerd + Geannuleerd Uitvoering is geannuleerd door de plugin van een 3e partij Eigenschappentype bestaat al @@ -1179,7 +1331,9 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je en zichtbaar op de website %0% documenten gepubliceerd en zichtbaar op de website %0% gepubliceerd en zichtbaar op de website - %0% documenten gepubliceerd voor de talen languages %1% en zichtbaar op de website + %0% documenten gepubliceerd voor de talen languages %1% en zichtbaar op + de website + Inhoud opgeslagen Vergeet niet te publiceren om de wijzigingen zichtbaar te maken Een planning voor publicatie is bijgewerkt @@ -1207,13 +1361,16 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Mediatype opgeslagen Ledentype opgeslagen Ledengroep opgeslagen + Er bestaat al een andere ledengroep met dezelfde naam Sjabloon niet opgeslagen Controleer dat je geen 2 sjablonen met dezelfde naam hebt Sjabloon opgeslagen Sjabloon opgeslagen zonder fouten! Inhoud gedepubliceerd Inhoud variatie %0% gedepubliceerd - De verplichte taal '%0%' is gedepubliceerd. Alle talen voor deze inhoud zijn nu gedepubliceerd. + De verplichte taal '%0%' is gedepubliceerd. Alle talen voor deze + inhoud zijn nu gedepubliceerd. + Partial view opgeslagen Partial view opgeslagen zonder fouten! Partial view niet opgeslagen @@ -1233,13 +1390,19 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Gebruiker %0% is verwijderd Gebruiker uitnodigen Uitnodiging is opnieuw gestuurd naar gebruiker %0% - Kan het document niet publiceren omdat de vereiste '%0%' niet is gepubliceerd + Kan het document niet publiceren omdat de vereiste '%0%' niet is + gepubliceerd + Validatie is mislukt voor de taal '%0%' Documenttype is geëxporteerd naar een bestand Er is een fout gebeurd tijdens het exporteren van het documenttype De publicatiedatum kan niet in het verleden liggen - Kan het document niet plannen voor publicatie omdat de vereiste '%0%' niet is gepubliceerd - Kan het document niet plannen voor publicatie omdat de vereiste '%0%' een publicatiedatum heeft die later is dan een niet-verplichte taal + Kan het document niet plannen voor publicatie omdat de vereiste '%0%' niet is + gepubliceerd + + Kan het document niet plannen voor publicatie omdat de vereiste '%0%' een + publicatiedatum heeft die later is dan een niet-verplichte taal + De vervaldatum kan niet in het verleden liggen De vervaldatum kan niet voor de publicatiedatum liggen @@ -1247,7 +1410,9 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Stijl toevoegen Stijl bewerken Rich text editor stijlen - Definieer de stijlen die beschikbaar moeten zijn in de rich text editor voor deze stylesheet + Definieer de stijlen die beschikbaar moeten zijn in de rich text editor voor deze + stylesheet + Stylesheet bewerken Stylesheet eigenschap bewerken Naam waarmee de stijl in de editor te kiezen is @@ -1269,32 +1434,37 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Invoegen Kies wat je wil invoegen in het sjabloon Woordenboek item invoegen - Een woordenboekitem is een tijdelijke aanduiding voor een vertaalbaar stuk tekst, waardoor het gemakkelijk is om ontwerpen voor meertalige websites te maken. + Een woordenboekitem is een tijdelijke aanduiding voor een vertaalbaar stuk + tekst, waardoor het gemakkelijk is om ontwerpen voor meertalige websites te maken. + Macro invoegen - Een Macro is een configureerbaar component die gebruikt kan worden voor - herbruikbare delen van je ontwerp, waar je de optie nodig hebt om parameters op te geven, - zoals bij gallerijen, formulieren en lijsten. + Een Macro is een configureerbaar component die gebruikt kan worden voor + herbruikbare delen van je ontwerp, waar je de optie nodig hebt om parameters op te geven, + zoals bij gallerijen, formulieren en lijsten. Umbraco pagina veld invoegen - Toont de waarde van een benoemd veld van de huidige pagina, met opties om de waarde te wijzigen of terug te vallen op alternatieve waarden. + Toont de waarde van een benoemd veld van de huidige pagina, met opties om de waarde + te wijzigen of terug te vallen op alternatieve waarden. + Partial view - Een partial view is een apart sjabloon dat kan gerendered worden in een ander sjabloon, - het is geschikt voor het hergebruiken van HTML of voor het scheiden van complexe sjablonen in afzonderlijke bestanden. + Een partial view is een apart sjabloon dat kan gerendered worden in een ander sjabloon, + het is geschikt voor het hergebruiken van HTML of voor het scheiden van complexe sjablonen in afzonderlijke + bestanden. Hoofdsjabloon Geen hoofdsjabloon Render onderliggend sjabloon - @RenderBody() in te voegen. ]]> Definieer een benoemde sectie - @section { ... } te omwikkelen. Dit kan worden weergegeven in een specifiek gebied van de bovenliggende sjabloon door @RenderSection te gebruiken. @@ -1302,7 +1472,7 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Render een benoemde sectie - @RenderSection(name) in te voegen. This renders an area of a child template which is wrapped in a corresponding @section [name]{ ... } definition. ]]> @@ -1310,7 +1480,7 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Sectienaam Sectie is verplicht - @section definiëren, anders wordt een fout getoond. ]]> @@ -1361,15 +1531,21 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Klik om een afbeelding in te voegen Typ hier... Grid lay-outs - Lay-outs zijn het globale werkgebied voor de grid editor. Je hebt meestal maar één of twee verschillende lay-outs nodig + Lay-outs zijn het globale werkgebied voor de grid editor. Je hebt meestal maar één of + twee verschillende lay-outs nodig + Een grid lay-out toevoegen Grid lay-out aanpassen - De lay-out aanpassen door de kolombreedte aan te passen en extra kolommen toe te voegen + De lay-out aanpassen door de kolombreedte aan te passen en extra kolommen toe te + voegen + Rijconfiguratie Rijen zijn voorgedefinieerde cellen die horizontaal zijn gerangschikt Een rijconfiguratie toevoegen Rijconfiguratie aanpassen - De rijconfiguratie aanpassen door de breedte van de cel in te stellen en extra cellen toe te voegen + De rijconfiguratie aanpassen door de breedte van de cel in te stellen en + extra cellen toe te voegen + Geen verdere instellingen beschikbaar Kolommen Het totaal aantal gecombineerde kolommen in de grid layout @@ -1387,7 +1563,8 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je zijn toegevoegd Je gaat de rijconfiguratie verwijderen - Een rijconfiguratienaam verwijderen zal er voor zorgen dat bestaande inhoud verloren gaat die gebaseerd is op deze configuratie. + Een rijconfiguratienaam verwijderen zal er voor zorgen dat bestaande inhoud verloren gaat die gebaseerd is op deze + configuratie. @@ -1399,18 +1576,30 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Eigenschap toevoegen Verplicht label Lijstweergave inschakelen - Laat de onderliggende nodes van het content item zien als een sorteer- en doorzoekbare lijstweergave. Deze onderliggende nodes worden dan niet in de boomstructuur getoond. + Laat de onderliggende nodes van het content item zien als een sorteer- en + doorzoekbare lijstweergave. Deze onderliggende nodes worden dan niet in de boomstructuur getoond. + Toegestane Sjablonen - Kies welke sjablonen toegestaan zijn om door de editors op dit contenttype gebruikt te worden + Kies welke sjablonen toegestaan zijn om door de editors op dit contenttype + gebruikt te worden + Sta toe op hoofdniveau Sta editors toe om inhoud van dit type aan te maken op hoofdniveau Toegestane onderliggende node types - Sta inhoud van een bepaald type toe om onder dit type aangemaakt te kunnen worden + Sta inhoud van een bepaald type toe om onder dit type aangemaakt te kunnen + worden + Kies onderliggende node - Overgeërfde tabs en properties van een bestaand documenttype. Nieuwe tabs worden toegevoegd aan het huidige documenttype of samengevoegd als een tab met dezelfde naam al bestaat. - Dit contenttype wordt gebruikt in een compositie en kan daarom niet zelf een compositie worden. + Overgeërfde tabs en properties van een bestaand documenttype. Nieuwe tabs + worden toegevoegd aan het huidige documenttype of samengevoegd als een tab met dezelfde naam al bestaat. + + Dit contenttype wordt gebruikt in een compositie en kan daarom niet zelf een + compositie worden. + Er zijn geen contenttypen beschikbaar om als compositie te gebruiken. - Een compositie verwijderen zal alle bijbehorende eigenschapsdata ook verwijderen. Zodra je het documenttype hebt opgeslagen is er geen weg meer terug. + Een compositie verwijderen zal alle bijbehorende eigenschapsdata ook + verwijderen. Zodra je het documenttype hebt opgeslagen is er geen weg meer terug. + Beschikbare editors Herbruik Editor instellingen @@ -1426,49 +1615,74 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Alle Documenttypes Alle documenten Alle media items - die gebruik maken van dit documenttype zullen permanent verwijderd worden. Bevestig aub dat je deze ook wilt verwijderen. - die gebruik maken van dit mediatype zullen permanent verwijderd worden. Bevestig aub dat je deze ook wilt verwijderen. - die gebruik maken van dit lidtype zullen permanent verwijderd worden. Bevestig aub dat je deze ook wilt verwijderen. + die gebruik maken van dit documenttype zullen permanent verwijderd worden. Bevestig + aub dat je deze ook wilt verwijderen. + + die gebruik maken van dit mediatype zullen permanent verwijderd worden. Bevestig aub dat + je deze ook wilt verwijderen. + + die gebruik maken van dit lidtype zullen permanent verwijderd worden. Bevestig aub dat + je deze ook wilt verwijderen. + en alle documenten van dit type en alle media items van dit type en alle leden van dit type Lid kan bewerken - Toestaan dat deze eigenschap kan worden gewijzigd door het lid op zijn profiel pagina. + Toestaan dat deze eigenschap kan worden gewijzigd door het lid op zijn profiel + pagina. + Omvat gevoelige gegevens - Verberg deze eigenschap voor de content editor die geen toegang heeft tot het bekijken van gevoelige informatie. + Verberg deze eigenschap voor de content editor die geen toegang heeft tot + het bekijken van gevoelige informatie. + Toon in het profiel van leden - Toelaten dat deze eigenschap wordt getoond op de profiel pagina van het lid. + Toelaten dat deze eigenschap wordt getoond op de profiel pagina van het + lid. + tab heeft geen sorteervolgorde Waar wordt deze compositie gebruikt? - Deze samenstelling wordt momenteel gebruikt bij de samenstelling van de volgende inhoudstypen: + Deze samenstelling wordt momenteel gebruikt bij de samenstelling van de + volgende inhoudstypen: + Variaties toestaan Variëren per cultuur toestaan Segmentatie toestaan Varieer per cultuur Varieer per segment - Editors toestaan om nieuwe inhoud aan te maken van dit type in verschillende talen. + Editors toestaan om nieuwe inhoud aan te maken van dit type in verschillende + talen. + Editors toestaan om nieuwe inhoud in verschillende talen te creëren Editors toestaan om nieuwe segmenten van deze inhoud te creëren. Variaties per cultuur toestaan Segmentatie toestaan Elementtype Is een elementtype - Een elementtype is bedoeld om bijvoorbeeld in geneste inhoud gebruikt te worden en niet in de boomstructuur. - Een documenttype kan niet worden gewijzigd in een elementtype nadat het is gebruikt om een of meer contentitems te maken. + Een elementtype is bedoeld om bijvoorbeeld in geneste inhoud gebruikt te worden en + niet in de boomstructuur. + + Een documenttype kan niet worden gewijzigd in een elementtype nadat het is gebruikt + om een of meer contentitems te maken. + Dit is niet van toepassing op een elementtype - Je hebt wijzigingen aangebracht aan deze eigenschap. Ben je zeker dat je ze wil weggooien? - Tabblad toevoegen + Je hebt wijzigingen aangebracht aan deze eigenschap. Ben je zeker dat je ze wil + weggooien? + Taal toevoegen Verplichte taal - Eigenschappen van deze taal moeten worden ingevuld voordat de node kan worden gepubliceerd. + Eigenschappen van deze taal moeten worden ingevuld voordat de node kan worden + gepubliceerd. + Standaard taal Een Umbraco site kan maar één standaardtaal hebben. Als u de standaardtaal wijzigt, kan er standaardinhoud ontbreken. Valt terug naar Geen terugvaltaal - Om meertalige inhoud terug te laten vallen naar een andere taal als deze niet aanwezig is in de gevraagde taal, selecteert u deze hier. + Om meertalige inhoud terug te laten vallen naar een andere taal als deze + niet aanwezig is in de gevraagde taal, selecteert u deze hier. + Terugvaltaal Geen @@ -1477,7 +1691,9 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Parameter bewerken Macro naam invoeren Parameters - Definieer de parameters die beschikbaar moeten zijn bij het gebruik van deze macro. + Definieer de parameters die beschikbaar moeten zijn bij het gebruik van deze + macro. + Selecteer een partial view macro bestand @@ -1517,7 +1733,7 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Speciale karakters in URL's worden geëncodeerd Zal alleen worden gebruikt waneer de bovenstaande veldwaardes leeg zijn Dit veld zal alleen worden gebruikt als het primaire veld leeg is - Ja, met tijd. Scheidingsteken: + Ja, met tijd. Scheidingsteken: Details van vertaling @@ -1539,13 +1755,17 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je De Umbraco Robot ]]> - Geen vertaal-gebruikers gevonden. Maak eerst een vertaal-gebruiker aan voordat je pagina's voor vertaling verstuurt + Geen vertaal-gebruikers gevonden. Maak eerst een vertaal-gebruiker aan voordat je + pagina's voor vertaling verstuurt + De pagina '%0%' is verstuurd voor vertaling Stuur voor vertaling Totaal aantal woorden Vertaal naar Vertaling voltooid. - Je kan een voorbeeld van vertaalde pagina's bekijken door hieronder te klikken. Als de originele pagina gevonden werd, wordt een vergelijking van beide pagina's getoond. + Je kan een voorbeeld van vertaalde pagina's bekijken door hieronder te klikken. Als + de originele pagina gevonden werd, wordt een vergelijking van beide pagina's getoond. + Vertalen niet gelukt, het XML-bestand is mogelijk beschadigd. Vertalingsopties Vertaler @@ -1594,11 +1814,15 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Nieuwe update beschikbaar %0% is gereed, klik hier om te downloaden Er is geen verbinding met de server - Er is een fout opgetreden bij het zoeken naar een update. Bekijk de trace-stack voor verdere informatie. + Er is een fout opgetreden bij het zoeken naar een update. Bekijk de trace-stack + voor verdere informatie. + Toegang - Gebaseerd op de gebruikersgroepen en startpagina's heeft de gebruiker toegang tot de volgende pagina's + Gebaseerd op de gebruikersgroepen en startpagina's heeft de gebruiker toegang tot de + volgende pagina's + Toegang geven Beheerders Categorieveld @@ -1609,10 +1833,14 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je is niet gedeblokkeerd Het wachtwoord is niet gewijzigd Bevestig nieuw password - Je kunt je wachtwoord veranderen door onderstaand formulier in te vullen en op de knop 'Verander wachtwoord' te klikken + Je kunt je wachtwoord veranderen door onderstaand formulier in te vullen en + op de knop 'Verander wachtwoord' te klikken + Inhoudskanaal Nog een gebruiker aanmaken - Maak nieuwe gebruikers aan om hun toegang te geven tot Umbraco. Wanneer een nieuwe gebruiker wordt aangemaakt wordt er een wachtwoord gegenereerd dat je met hun kan delen. + Maak nieuwe gebruikers aan om hun toegang te geven tot Umbraco. Wanneer een nieuwe + gebruiker wordt aangemaakt wordt er een wachtwoord gegenereerd dat je met hun kan delen. + Omschrijving Geblokkeerde gebruiker Documenttype @@ -1622,7 +1850,9 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Ga naar gebruikersprofiel Voeg gebruikersgroepen toe om rechten in te stellen Nog een gebruiker uitnodigen - Nodig gebruikers uit om hen toegang te geven to Umbraco. Een uitnodiging wordt via e-mail verstuurd met instructies hoe de gebruiker kan inloggen. + Nodig gebruikers uit om hen toegang te geven to Umbraco. Een uitnodiging wordt via + e-mail verstuurd met instructies hoe de gebruiker kan inloggen. + Taal Stel de taal in die gebruiker zal zien in menu's en dialoogvensters Laatst geblokkeerd datum @@ -1667,15 +1897,23 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Beperk de Inhoud tot specifieke startnodes Laatste keer bijgewerkt is aangemaakt - De gebruiker is aangemaakt. Om in te loggen in Umbraco gebruik je onderstaand wachtwoord. + De gebruiker is aangemaakt. Om in te loggen in Umbraco gebruik je onderstaand + wachtwoord. + Gebruikers beheren Gebruikersnaam Gebruikersrechten Gebruikersgroep is uitgenodigd - Een uitnodiging is gestuurd naar de nieuwe gebruiker met informatie over hoe in te loggen in Umbraco - Hallo en welkom in Umbraco! Binnen ongeveer één minuut kan je aan de slag. Je moet enkel je wachtwoord instellen en een foto toevoegen. - Welkom bij Umbraco! Helaas is je uitnodiging vervallen. Vraag aan je administrator om de uitnodiging opnieuw te versturen. + Een uitnodiging is gestuurd naar de nieuwe gebruiker met informatie over hoe in + te loggen in Umbraco + + Hallo en welkom in Umbraco! Binnen ongeveer één minuut kan je aan de slag. Je + moet enkel je wachtwoord instellen en een foto toevoegen. + + Welkom bij Umbraco! Helaas is je uitnodiging vervallen. Vraag aan je + administrator om de uitnodiging opnieuw te versturen. + Wijzig je foto zodat andere gebruikers je makkelijk kunnen herkennen. Auteur Wijzig @@ -1829,14 +2067,21 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je 3: Configuration file path --> Waarde is insteld naar the aanbevolen waarde: '%0%'. - De verwachte waarde voor '%2%' is '%1%' in configuratiebestand '%3%', maar is '%0%'. - Onverwachte waarde '%0%' gevonden voor '%2%' in configuratiebestand '%3%'. + De verwachte waarde voor '%2%' is '%1%' in configuratiebestand + '%3%', maar is '%0%'. + + Onverwachte waarde '%0%' gevonden voor '%2%' in configuratiebestand + '%3%'. + Macro foutmeldingen zijn ingesteld op'%0%'. - Macro foutmeldingen zijn ingesteld op '%0%'. Dit zal er voor zorgen dat bepaalde, of alle, pagina's van de website niet geladen kunnen worden als er errors in een Macro zitten. Corrigeren zal deze waarde aanpassen naar '%1%'. + Macro foutmeldingen zijn ingesteld op '%0%'. Dit zal er voor zorgen dat + bepaalde, of alle, pagina's van de website niet geladen kunnen worden als er errors in een Macro zitten. + Corrigeren zal deze waarde aanpassen naar '%1%'. + Debug compilatie mode staat uit. - Debug compilatie mode staat momenteel aan. Wij raden aan deze instelling uit te zetten voor livegang. + Debug compilatie mode staat momenteel aan. Wij raden aan deze + instelling uit te zetten voor livegang. + @@ -1861,27 +2108,42 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je - X-Frame-Options header of meta-tag om IFRAMEing door andere websites te voorkomen is aanwezig!]]> - X-Frame-Options header of meta-tag om IFRAMEing door andere websites te voorkomen is NIET aanwezig.]]> - X-Content-Type-Options die beveiligt tegen MIME sniffing kwetsbaarheden is gevonden.]]> - X-Content-Type-Options die beveiligt tegen MIME sniffing kwetsbaarheden is niet gevonden.]]> - Strict-Transport-Security header, ook bekend als de HSTS-header, is gevonden.]]> - Strict-Transport-Securityheader is niet gevonden.]]> - X-XSS-Protection is gevonden.]]> - X-XSS-Protection is niet gevonden.]]> + + X-Frame-Options header of meta-tag om IFRAMEing door andere websites te voorkomen is aanwezig!]]> + + X-Frame-Options header of meta-tag om IFRAMEing door andere websites te voorkomen is NIET aanwezig.]]> + + X-Content-Type-Options die beveiligt tegen MIME sniffing kwetsbaarheden is gevonden.]]> + + X-Content-Type-Options die beveiligt tegen MIME sniffing kwetsbaarheden is niet gevonden.]]> + + Strict-Transport-Security header, ook bekend als de HSTS-header, is gevonden.]]> + + Strict-Transport-Securityheader is niet gevonden.]]> + + X-XSS-Protection is gevonden.]]> + + X-XSS-Protection is niet gevonden.]]> - %0%.]]> - Er zijn geen headers gevonden die informatie vrijgeven over de gebruikte website technologie! - SMTP instellingen zijn correct ingesteld en werken zoals verwacht. - %0%.]]> - %0%.]]> -

      Resultaten van de geplande Umbraco Health Checks uitgevoerd op %0% op %1%:

      %2%]]>
      + + %0%.]]> + Er zijn geen headers gevonden die informatie vrijgeven over de gebruikte + website technologie! + + SMTP instellingen zijn correct ingesteld en werken zoals verwacht. + + + %0%.]]> + + %0%.]]> + +

      Resultaten van de geplande Umbraco Health Checks uitgevoerd op %0% op %1%:

      %2%]]>
      Umbraco Health Check Status: %0% Groep controleren - De health checker evalueert verschillende delen van de website voor best practice instellingen, configuratie, mogelijke problemen, enzovoort. U kunt problemen eenvoudig oplossen met een druk op de knop. U kunt uw eigen health checks toevoegen, kijk even naar de documentatie voor meer informatie over aangepaste health checks.

      ]]> @@ -1896,15 +2158,21 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Redirect Url Beheer De volgende URLs verwijzen naar dit content item: Er zijn geen redirects - Er wordt automatisch een redirect aangemaakt als een gepubliceerde pagina hernoemd of verplaatst wordt. + Er wordt automatisch een redirect aangemaakt als een gepubliceerde pagina + hernoemd of verplaatst wordt. + Redirect URL verwijderd. Fout bij verwijderen redirect URL. Dit zal de redirect verwijderen Weet je zeker dat je de URL tracker wilt uitzetten? URL tracker staat nu uit. - Fout bij het uitzetten van de URL Tracker. Meer informatie kan gevonden worden in de log file. + Fout bij het uitzetten van de URL Tracker. Meer informatie kan gevonden worden in de log + file. + URL tracker staat nu aan. - Fout bij het aanzetten van de URL tracker. Meer informatie kan gevonden worden in de log file. + Fout bij het aanzetten van de URL tracker. Meer informatie kan gevonden worden in de log + file. + Geen woordenboekitems om uit te kiezen @@ -1917,7 +2185,9 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Content verwijderd met id : {0} gerelateerd aan aan bovenliggend item met Id: {1} Media verwijderd met id: {0} gerelateerd aan aan bovenliggend item met Id: {1} Kan dit item niet automatisch herstellen - Er is geen locatie waar dit item automatisch kan worden hersteld. U kunt het item handmatig verplaatsen met behulp van de onderstaande boomstructuur. + Er is geen locatie waar dit item automatisch kan worden hersteld. U kunt + het item handmatig verplaatsen met behulp van de onderstaande boomstructuur. + was hersteld onder @@ -2056,7 +2326,6 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Eigenschapsacties sluiten - Wachten Status vernieuwen Geheugencache @@ -2113,7 +2382,7 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Je bent slechts een klik verwijderd van uren aan Umbraco trainingvideo's. - Wil je Umbraco onder de knie krijgen? Besteed een paar minuten aan het leren van enkele best practices door een van deze video's over het gebruik van Umbraco te bekijken. Bezoek umbraco.tv voor meer Umbraco videos

      ]]>
      @@ -2121,41 +2390,49 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Start hier - Deze sectie bevat de bouwstenen voor jouw Umbraco-site. Volg de onderstaande links voor meer informatie over het werken met de items in de sectie Instellingen + Deze sectie bevat de bouwstenen voor jouw Umbraco-site. Volg de onderstaande links + voor meer informatie over het werken met de items in de sectie Instellingen + Meer te weten komen - in het Documentatiegedeelte van Our Umbraco ]]> - Community Forum ]]> - instructievideo's (sommige zijn gratis, andere vereisen een abonnement) ]]> - productiviteitsverhogende programma's en commerciële ondersteuning ]]> - training en certificering opportuniteiten ]]> Welkom bij Het Vriendelijke CMS - Bedankt om voor Umbraco te kiezen - We denken dat dit het begin van iets moois is. Hoewel het in het begin misschien overweldigend aanvoelt, hebben we er veel aan gedaan om de leercurve zo soepel en snel mogelijk te laten verlopen. + Bedankt om voor Umbraco te kiezen - We denken dat dit het begin van iets moois is. + Hoewel het in het begin misschien overweldigend aanvoelt, hebben we er veel aan gedaan om de leercurve zo soepel + en snel mogelijk te laten verlopen. + Umbraco Forms - Maak formulieren met behulp van een intuïtieve interface. Van eenvoudige contactformulieren die e-mails versturen tot geavanceerde vragenlijsten die integreren met CRM-systemen. Je klanten zullen er dol op zijn! + Maak formulieren met behulp van een intuïtieve interface. Van eenvoudige + contactformulieren die e-mails versturen tot geavanceerde vragenlijsten die integreren met CRM-systemen. Je + klanten zullen er dol op zijn! + Nieuwe blok aanmaken @@ -2175,14 +2452,20 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Label Aangepaste weergave Aangepaste weergave-omschrijving tonen - Overschrijf hoe dit blok wordt weergegeven in de BackOffice-gebruikersinterface. Kies een .html-bestand met je presentatie. + Overschrijf hoe dit blok wordt weergegeven in de + BackOffice-gebruikersinterface. Kies een .html-bestand met je presentatie. + Instellingen model Grootte van overlay-editor Aangepaste weergave toevoegen Instellingen toevoegen - %0% wil verwijderen?]]> - %0% wil verwijderen?]]> - De inhoud van dit blok is nog steeds aanwezig, bewerken van deze inhoud is niet langer mogelijk en wordt weergegeven als niet-ondersteunde inhoud. + + %0% wil verwijderen?]]> + + %0% wil verwijderen?]]> + De inhoud van dit blok is nog steeds aanwezig, bewerken van deze inhoud is + niet langer mogelijk en wordt weergegeven als niet-ondersteunde inhoud. + Miniatuur Miniatuur toevoegen @@ -2197,14 +2480,18 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Fout! Het Elementtype van dit blok bestaat niet meer Inhoud toevoegen - Eigenschap '%0%' gebruikt editor '%1%' die niet ondersteund wordt in blokken. + Eigenschap '%0%' gebruikt editor '%1%' die niet ondersteund wordt in + blokken. + Wat zijn Inhoudssjablonen? - Inhoudssjablonen is vooraf gedefinieerde inhoud die kan worden geselecteerd bij het maken van een nieuwe node. + Inhoudssjablonen is vooraf gedefinieerde inhoud die kan worden geselecteerd bij het + maken van een nieuwe node. + Hoe maak ik een Inhoudssjabloon? - Er zijn 2 manieren om Inhoudssjablonen te maken:

      • Klik met de rechtermuisknop op een inhoudsnode en selecteer "Inhoudssjabloon aanmaken" om een nieuwe Inhoudssjabloon te maken.
      • @@ -2214,6 +2501,9 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je ]]> Hoe beheer ik Inhoudssjablonen? - U kunt Inhoudssjablonen bewerken en verwijderen vanuit de boomstructuur "inhoudssjablonen" in de sectie Instellingen. Vouw het documenttype uit waarop de Inhoudssjabloon is gebaseerd en klik erop om het te bewerken of te verwijderen. + U kunt Inhoudssjablonen bewerken en verwijderen vanuit de boomstructuur + "inhoudssjablonen" in de sectie Instellingen. Vouw het documenttype uit waarop de Inhoudssjabloon is gebaseerd en + klik erop om het te bewerken of te verwijderen. + diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml b/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml index 2a0d170c0e87..dfbc324df603 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml @@ -192,7 +192,7 @@ Korzeń zawartości - Stwórz nowy Szablon Zawartości z '%0%' + %0%]]> Pusty Wybierz Szablon Zawartości Szablon Zawartości został stworzony diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml index 4ebfe2cc0a4f..9c1d9e12fb2d 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml @@ -95,7 +95,7 @@ Наблюдать за - Создать новый шаблон содержимого из '%0%' + %0%]]> Пустой Выбрать шаблон содержимого Шаблон содержимого создан diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml b/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml index fd8202a08fd1..e0e2235ae98d 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml @@ -98,7 +98,7 @@ Historik (alla varianter) - Skapa en ny innehållsmall för '%0%' + %0%]]> Tom Välj en innehållsmall Innehållsmall skapad diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/tr.xml b/src/Umbraco.Web.UI/umbraco/config/lang/tr.xml index 722bdbc21deb..58c0f7f94bfb 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/tr.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/tr.xml @@ -291,7 +291,7 @@ Bu öğe Geri Dönüşüm Kutusu'nda - '%0%' den yeni bir İçerik Şablonu oluşturun + %0% den yeni bir İçerik Şablonu oluşturun]]> Boş Bir İçerik Şablonu Seçin İçerik Şablonu oluşturuldu @@ -2248,7 +2248,6 @@ Web sitenizi yönetmek için, Umbraco'nun arka ofisini açın ve içerik eklemey Özellik Eylemlerini Kapat - Bekle Durumu yenile Bellek Önbelleği diff --git a/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Content/content.ts b/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Content/content.ts index 6cd543af29c1..3b220fc2f0d0 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Content/content.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Content/content.ts @@ -759,7 +759,8 @@ context('Content', () => { // Click macro cy.get(':nth-child(4) > .umb-card-grid-item > :nth-child(1)').click(); // Select the macro - cy.get('.umb-card-grid-item').contains(macroName).click(); + cy.get(`.umb-card-grid-item[title='${macroName}']`).click('bottom'); + // Save and publish cy.umbracoButtonByLabelKey('buttons_saveAndPublish').click(); diff --git a/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/scripts.ts b/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/scripts.ts index 430f8aa10877..3d7bd9dfca98 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/scripts.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/scripts.ts @@ -24,6 +24,9 @@ context('Scripts', () => { cy.umbracoContextMenuAction("action-create").click(); cy.get('.menu-label').first().click(); // TODO: Fucked we cant use something like cy.umbracoContextMenuAction("action-mediaType").click(); + //We have to wait here till everything is loaded, or worker will throw error + cy.intercept('/umbraco/lib/ace-builds/src-min-noconflict/worker-javascript.js').as('aceWorker'); + cy.wait('@aceWorker'); //Type name cy.umbracoEditorHeaderName(name); @@ -33,6 +36,8 @@ context('Scripts', () => { //Assert cy.umbracoSuccessNotification().should('be.visible'); + + cy.umbracoScriptExists(fileName).should('be.true'); diff --git a/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/stylesheets.ts b/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/stylesheets.ts index 2a1286c49931..0ebb733bc1ec 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/stylesheets.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/stylesheets.ts @@ -18,7 +18,9 @@ context('Stylesheets', () => { cy.umbracoContextMenuAction("action-create").click(); cy.get('.menu-label').first().click(); // TODO: Fucked we cant use something like cy.umbracoContextMenuAction("action-mediaType").click(); - + //We have to wait here till everything is loaded, or worker will throw error + cy.intercept('/umbraco/lib/ace-builds/src-min-noconflict/worker-css.js').as('aceWorker'); + cy.wait('@aceWorker'); //Type name cy.umbracoEditorHeaderName(name); diff --git a/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts b/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts index f73174f531a0..536adaf6fbfd 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Settings/templates.ts @@ -136,7 +136,7 @@ context('Templates', () => { // Insert macro cy.umbracoButtonByLabelKey('general_insert').click(); cy.get('.umb-insert-code-box__title').contains('Macro').click(); - cy.get('.umb-card-grid-item').contains(name).click(); + cy.get(`.umb-card-grid-item[title='${name}']`).click('bottom'); // Assert cy.get('.ace_content').contains('@await Umbraco.RenderMacroAsync("' + name + '")').should('exist'); diff --git a/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Tabs/tabs.ts b/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Tabs/tabs.ts index 92365d742610..196a104518f7 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Tabs/tabs.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/cypress/integration/Tabs/tabs.ts @@ -1,29 +1,29 @@ /// -import { - DocumentTypeBuilder, +import { + DocumentTypeBuilder, AliasHelper } from 'umbraco-cypress-testhelpers'; - + const tabsDocTypeName = 'Tabs Test Document'; const tabsDocTypeAlias = AliasHelper.toAlias(tabsDocTypeName); - + context('Tabs', () => { - + beforeEach(() => { cy.umbracoLogin(Cypress.env('username'), Cypress.env('password'), false); }); - + afterEach(() => { cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName) }); - + function OpenDocTypeFolder(){ cy.umbracoSection('settings'); cy.get('li .umb-tree-root:contains("Settings")').should("be.visible"); cy.get('.umb-tree-item__inner > .umb-tree-item__arrow').eq(0).click(); cy.get('.umb-tree-item__inner > .umb-tree-item__label').contains(tabsDocTypeName).click(); } - + function CreateDocWithTabAndNavigate(){ cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName); const tabsDocType = new DocumentTypeBuilder() @@ -44,8 +44,8 @@ import { cy.saveDocumentType(tabsDocType); OpenDocTypeFolder(); } - - it('Create tab', () => { + + it('Create tab', () => { cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName); cy.deleteAllContent(); const tabsDocType = new DocumentTypeBuilder() @@ -72,13 +72,13 @@ import { cy.get('[aria-hidden="false"] > .umb-box-content > .umb-group-builder__group-add-property').click(); cy.get('.editor-label').type('property name'); cy.get('[data-element="editor-add"]').click(); - + //Search for textstring cy.get('#datatype-search').type('Textstring'); - + // Choose first item cy.get('[title="Textstring"]').closest("li").click(); - + // Save property cy.get('.btn-success').last().click(); cy.umbracoButtonByLabelKey('buttons_save').click(); @@ -87,13 +87,13 @@ import { cy.get('[title="tab1"]').should('be.visible'); cy.get('[title="tab2"]').should('be.visible'); }); - - it('Delete tabs', () => { + + it('Delete tabs', () => { CreateDocWithTabAndNavigate(); //Check if tab is there, else if it wasnt created, this test would always pass cy.get('[title="aTab 1"]').should('be.visible'); //Delete a tab - cy.get('.btn-reset > .icon-trash').click(); + cy.get('.btn-reset > [icon="icon-trash"]').first().click(); cy.get('.umb-button > .btn').last().click(); cy.umbracoButtonByLabelKey('buttons_save').click(); //Assert @@ -101,7 +101,7 @@ import { //Clean cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName); }); - + it('Delete property in tab', () => { cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName); const tabsDocType = new DocumentTypeBuilder() @@ -132,7 +132,7 @@ import { cy.get('[title=urlPicker]').should('be.visible'); cy.get('[title=picker]').should('not.exist'); }); - + it('Delete group in tab', () => { cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName); const tabsDocType = new DocumentTypeBuilder() @@ -159,7 +159,7 @@ import { cy.saveDocumentType(tabsDocType); OpenDocTypeFolder(); //Delete group - cy.get('.umb-group-builder__group-remove > .icon-trash').eq(1).click(); + cy.get('.umb-group-builder__group-remove > [icon="icon-trash"]').eq(1).click(); cy.umbracoButtonByLabelKey('actions_delete').click(); cy.umbracoButtonByLabelKey('buttons_save').click() //Assert @@ -167,7 +167,7 @@ import { cy.get('[title=picker]').should('be.visible'); cy.get('[title=urlPicker]').should('not.exist'); }); - + it('Reorders tab', () => { cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName); const tabsDocType = new DocumentTypeBuilder() @@ -219,7 +219,7 @@ import { cy.get('.umb-group-builder__group-title-input').eq(1).invoke('attr', 'title').should('eq', 'aTab 3') cy.get('.umb-group-builder__group-title-input').eq(2).invoke('attr', 'title').should('eq', 'aTab 1') }); - + it('Reorders groups in a tab', () => { cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName); const tabsDocType = new DocumentTypeBuilder() @@ -249,7 +249,7 @@ import { OpenDocTypeFolder(); cy.get('[alias="reorder"]').click(); cy.get('.umb-property-editor-tiny').eq(2).type('1'); - + cy.get('[alias="reorder"]').click(); cy.umbracoButtonByLabelKey('buttons_save').click(); //Assert @@ -257,7 +257,7 @@ import { cy.get('.umb-group-builder__group-title-input').eq(2) .invoke('attr', 'title').should('eq', 'aTab 1/aTab group 2'); }); - + it('Reorders properties in a tab', () => { cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName); const tabsDocType = new DocumentTypeBuilder() @@ -286,12 +286,12 @@ import { cy.get('[alias="reorder"]').click(); cy.get('.umb-group-builder__group-sort-value').first().type('2'); cy.get('[alias="reorder"]').click(); - cy.umbracoButtonByLabelKey('buttons_save').click(); + cy.umbracoButtonByLabelKey('buttons_save').click(); //Assert cy.umbracoSuccessNotification().should('be.visible'); cy.get('.umb-locked-field__input').last().invoke('attr', 'title').should('eq', 'urlPicker'); }); - + it('Tab name cannot be empty', () => { CreateDocWithTabAndNavigate(); cy.get('.umb-group-builder__group-title-input').first().clear(); @@ -299,7 +299,7 @@ import { //Assert cy.umbracoErrorNotification().should('be.visible'); }); - + it('Two tabs cannot have the same name', () => { cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName); const tabsDocType = new DocumentTypeBuilder() @@ -326,7 +326,7 @@ import { //Assert cy.umbracoErrorNotification().should('be.visible'); }); - + it('Group name cannot be empty', () => { CreateDocWithTabAndNavigate(); cy.get('.clearfix > .-placeholder').click(); @@ -334,7 +334,7 @@ import { //Assert cy.umbracoErrorNotification().should('be.visible'); }); - + it('Group name cannot have the same name', () => { CreateDocWithTabAndNavigate(); cy.get('.clearfix > .-placeholder').click(); @@ -343,7 +343,7 @@ import { //Assert cy.umbracoErrorNotification().should('be.visible'); }); - + it('Drag a group into another tab', () => { cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName); const tabsDocType = new DocumentTypeBuilder() @@ -394,7 +394,7 @@ import { cy.umbracoSuccessNotification().should('be.visible'); cy.get('[title="aTab 1/aTab group 2"]').should('be.visible'); }); - + it('Drag and drop reorders a tab', () => { cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName); const tabsDocType = new DocumentTypeBuilder() @@ -446,7 +446,7 @@ import { cy.umbracoSuccessNotification().should('be.visible'); cy.get('[title="aTab 2"]').should('be.visible'); }); - + it('Drags and drops a property in a tab', () => { cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName); const tabsDocType = new DocumentTypeBuilder() @@ -502,7 +502,7 @@ import { cy.umbracoSuccessNotification().should('be.visible'); cy.get('[title="urlPickerTabTwo"]').should('be.visible'); }); - + it('Drags and drops a group and converts to tab', () => { cy.umbracoEnsureDocumentTypeNameNotExists(tabsDocTypeName); const tabsDocType = new DocumentTypeBuilder() @@ -549,4 +549,4 @@ import { cy.umbracoSuccessNotification().should('be.visible'); cy.get('[title="tabGroup"]').should('be.visible'); }); - }); \ No newline at end of file + }); diff --git a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json index e185dd053e90..2eb6cfa471fc 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json @@ -1,2884 +1,8 @@ { - "name": "Umbraco.Tests.AcceptanceTest", - "lockfileVersion": 2, + "name": "acceptancetest", "requires": true, - "packages": { - "": { - "hasInstallScript": true, - "dependencies": { - "typescript": "^3.9.2" - }, - "devDependencies": { - "cross-env": "^7.0.2", - "cypress": "^6.8.0", - "del": "^6.0.0", - "ncp": "^2.0.0", - "prompt": "^1.2.0", - "umbraco-cypress-testhelpers": "^1.0.0-beta-58" - } - }, - "node_modules/@cypress/listr-verbose-renderer": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@cypress/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz", - "integrity": "sha1-p3SS9LEdzHxEajSz4ochr9M8ZCo=", - "dev": true, - "dependencies": { - "chalk": "^1.1.3", - "cli-cursor": "^1.0.2", - "date-fns": "^1.27.2", - "figures": "^1.7.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@cypress/listr-verbose-renderer/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@cypress/listr-verbose-renderer/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@cypress/listr-verbose-renderer/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@cypress/request": { - "version": "2.88.6", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.6.tgz", - "integrity": "sha512-z0UxBE/+qaESAHY9p9sM2h8Y4XqtsbDCt0/DPOrqA/RZgKi4PkxdpXyK4wCCnSk1xHqWHZZAE+gV6aDAR6+caQ==", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@cypress/xvfb": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", - "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", - "dev": true, - "dependencies": { - "debug": "^3.1.0", - "lodash.once": "^4.1.1" - } - }, - "node_modules/@cypress/xvfb/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@samverschueren/stream-to-observable": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz", - "integrity": "sha512-c/qwwcHyafOQuVQJj0IlBjf5yYgBI7YPJ77k4fOJYesb41jio65eaJODRUmfYKhTOFBrIZ66kgvGPlNbjuoRdQ==", - "dev": true, - "dependencies": { - "any-observable": "^0.3.0" - }, - "engines": { - "node": ">=6" - }, - "peerDependenciesMeta": { - "rxjs": { - "optional": true - }, - "zen-observable": { - "optional": true - } - } - }, - "node_modules/@types/node": { - "version": "12.12.50", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.50.tgz", - "integrity": "sha512-5ImO01Fb8YsEOYpV+aeyGYztcYcjGsBvN4D7G5r1ef2cuQOpymjWNQi5V0rKHE6PC2ru3HkoUr/Br2/8GUA84w==", - "dev": true - }, - "node_modules/@types/sinonjs__fake-timers": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.4.tgz", - "integrity": "sha512-IFQTJARgMUBF+xVd2b+hIgXWrZEjND3vJtRCvIelcFB5SIXfjV4bOHbHJ0eXKh+0COrBRc8MqteKAz/j88rE0A==", - "dev": true - }, - "node_modules/@types/sizzle": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", - "dev": true - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/aggregate-error/node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/any-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", - "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/async": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.1.tgz", - "integrity": "sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==", - "dev": true - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/blob-util": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", - "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", - "dev": true - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/cachedir": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", - "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelize": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", - "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=", - "dev": true - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/check-more-types": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "dev": true, - "dependencies": { - "restore-cursor": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cli-table3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz", - "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", - "dev": true, - "dependencies": { - "object-assign": "^4.1.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "colors": "^1.1.2" - } - }, - "node_modules/cli-truncate": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", - "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", - "dev": true, - "dependencies": { - "slice-ansi": "0.0.4", - "string-width": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cli-truncate/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/common-tags": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", - "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cycle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", - "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/cypress": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-6.9.1.tgz", - "integrity": "sha512-/RVx6sOhsyTR9sd9v0BHI4tnDZAhsH9rNat7CIKCUEr5VPWxyfGH0EzK4IHhAqAH8vjFcD4U14tPiJXshoUrmQ==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@cypress/listr-verbose-renderer": "^0.4.1", - "@cypress/request": "^2.88.5", - "@cypress/xvfb": "^1.2.4", - "@types/node": "12.12.50", - "@types/sinonjs__fake-timers": "^6.0.1", - "@types/sizzle": "^2.3.2", - "arch": "^2.1.2", - "blob-util": "2.0.2", - "bluebird": "^3.7.2", - "cachedir": "^2.3.0", - "chalk": "^4.1.0", - "check-more-types": "^2.24.0", - "cli-table3": "~0.6.0", - "commander": "^5.1.0", - "common-tags": "^1.8.0", - "dayjs": "^1.9.3", - "debug": "4.3.2", - "eventemitter2": "^6.4.2", - "execa": "^4.0.2", - "executable": "^4.1.1", - "extract-zip": "^1.7.0", - "fs-extra": "^9.0.1", - "getos": "^3.2.1", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.3.2", - "lazy-ass": "^1.6.0", - "listr": "^0.14.3", - "lodash": "^4.17.19", - "log-symbols": "^4.0.0", - "minimist": "^1.2.5", - "moment": "^2.29.1", - "ospath": "^1.2.2", - "pretty-bytes": "^5.4.1", - "ramda": "~0.27.1", - "request-progress": "^3.0.0", - "supports-color": "^7.2.0", - "tmp": "~0.2.1", - "untildify": "^4.0.0", - "url": "^0.11.0", - "yauzl": "^2.10.0" - }, - "bin": { - "cypress": "bin/cypress" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", - "dev": true - }, - "node_modules/dayjs": { - "version": "1.10.7", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", - "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==", - "dev": true - }, - "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", - "dev": true, - "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/elegant-spinner": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", - "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eventemitter2": { - "version": "6.4.5", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", - "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==", - "dev": true - }, - "node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/executable": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", - "dev": true, - "dependencies": { - "pify": "^2.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extract-zip": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", - "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", - "dev": true, - "dependencies": { - "concat-stream": "^1.6.2", - "debug": "^2.6.9", - "mkdirp": "^0.5.4", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - } - }, - "node_modules/extract-zip/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/extract-zip/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", - "dev": true, - "engines": { - "node": "> 0.1.90" - } - }, - "node_modules/faker": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/faker/-/faker-4.1.0.tgz", - "integrity": "sha1-HkW7vsxndLPBlfrSg1EJxtdIzD8=", - "dev": true - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/getos": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", - "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", - "dev": true, - "dependencies": { - "async": "^3.2.0" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/global-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", - "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", - "dev": true, - "dependencies": { - "ini": "1.3.7" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, - "engines": { - "node": ">=8.12.0" - } - }, - "node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", - "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", - "dev": true - }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "dependencies": { - "ci-info": "^2.0.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-installed-globally": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", - "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", - "dev": true, - "dependencies": { - "global-dirs": "^2.0.1", - "is-path-inside": "^3.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-observable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", - "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", - "dev": true, - "dependencies": { - "symbol-observable": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "node_modules/lazy-ass": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", - "dev": true, - "engines": { - "node": "> 0.8" - } - }, - "node_modules/listr": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", - "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", - "dev": true, - "dependencies": { - "@samverschueren/stream-to-observable": "^0.3.0", - "is-observable": "^1.1.0", - "is-promise": "^2.1.0", - "is-stream": "^1.1.0", - "listr-silent-renderer": "^1.1.1", - "listr-update-renderer": "^0.5.0", - "listr-verbose-renderer": "^0.5.0", - "p-map": "^2.0.0", - "rxjs": "^6.3.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/listr-silent-renderer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", - "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/listr-update-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", - "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", - "dev": true, - "dependencies": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^2.3.0", - "strip-ansi": "^3.0.1" - }, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "listr": "^0.14.2" - } - }, - "node_modules/listr-update-renderer/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/listr-update-renderer/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/listr-update-renderer/node_modules/log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "dev": true, - "dependencies": { - "chalk": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/listr-update-renderer/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/listr-verbose-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", - "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.1", - "cli-cursor": "^2.1.0", - "date-fns": "^1.27.2", - "figures": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/listr-verbose-renderer/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/listr-verbose-renderer/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/listr-verbose-renderer/node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/listr-verbose-renderer/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/listr-verbose-renderer/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/listr-verbose-renderer/node_modules/figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/listr-verbose-renderer/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/listr-verbose-renderer/node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/listr-verbose-renderer/node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/listr-verbose-renderer/node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/listr-verbose-renderer/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/listr/node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/listr/node_modules/p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", - "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", - "dev": true, - "dependencies": { - "ansi-escapes": "^3.0.0", - "cli-cursor": "^2.0.0", - "wrap-ansi": "^3.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/log-update/node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/log-update/node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/log-update/node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/log-update/node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", - "dev": true, - "dependencies": { - "mime-db": "1.50.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", - "dev": true, - "bin": { - "ncp": "bin/ncp" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ospath": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", - "integrity": "sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=", - "dev": true - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/prompt": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/prompt/-/prompt-1.2.0.tgz", - "integrity": "sha512-iGerYRpRUg5ZyC+FJ/25G5PUKuWAGRjW1uOlhX7Pi3O5YygdK6R+KEaBjRbHSkU5vfS5PZCltSPZdDtUYwRCZA==", - "dev": true, - "dependencies": { - "async": "~0.9.0", - "colors": "^1.1.2", - "read": "1.0.x", - "revalidator": "0.1.x", - "winston": "2.x" - }, - "engines": { - "node": ">= 0.6.6" - } - }, - "node_modules/prompt/node_modules/async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", - "dev": true - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "dev": true, - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ramda": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", - "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", - "dev": true - }, - "node_modules/read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", - "dev": true, - "dependencies": { - "mute-stream": "~0.0.4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/request-progress": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=", - "dev": true, - "dependencies": { - "throttleit": "^1.0.0" - } - }, - "node_modules/restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "dev": true, - "dependencies": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/revalidator": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", - "integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", - "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/throttleit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", - "dev": true - }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "node_modules/typescript": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", - "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/umbraco-cypress-testhelpers": { - "version": "1.0.0-beta-58", - "resolved": "https://registry.npmjs.org/umbraco-cypress-testhelpers/-/umbraco-cypress-testhelpers-1.0.0-beta-58.tgz", - "integrity": "sha512-qbkqGo+g4FzQTstYQXPYDjJyVRH+guNZt1WZXQ8v64dTucN/Ku/noowMA9y6q0mLOZ8+SR9xmMySHfa7E48Vfw==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "camelize": "^1.0.0", - "faker": "^4.1.0" - }, - "peerDependencies": { - "cross-env": "^7.0.2", - "cypress": "^6.8.0", - "ncp": "^2.0.0" - } - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/verror/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/winston": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.5.tgz", - "integrity": "sha512-TWoamHt5yYvsMarGlGEQE59SbJHqGsZV8/lwC+iCcGeAe0vUaOh+Lv6SYM17ouzC/a/LB1/hz/7sxFBtlu1l4A==", - "dev": true, - "dependencies": { - "async": "~1.0.0", - "colors": "1.0.x", - "cycle": "1.0.x", - "eyes": "0.1.x", - "isstream": "0.1.x", - "stack-trace": "0.0.x" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/winston/node_modules/async": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", - "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", - "dev": true - }, - "node_modules/winston/node_modules/colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/wrap-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", - "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", - "dev": true, - "dependencies": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - } - }, + "lockfileVersion": 1, "dependencies": { - "@cypress/listr-verbose-renderer": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@cypress/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz", - "integrity": "sha1-p3SS9LEdzHxEajSz4ochr9M8ZCo=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-cursor": "^1.0.2", - "date-fns": "^1.27.2", - "figures": "^1.7.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, "@cypress/request": { "version": "2.88.6", "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.6.tgz", @@ -2953,19 +77,10 @@ "fastq": "^1.6.0" } }, - "@samverschueren/stream-to-observable": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz", - "integrity": "sha512-c/qwwcHyafOQuVQJj0IlBjf5yYgBI7YPJ77k4fOJYesb41jio65eaJODRUmfYKhTOFBrIZ66kgvGPlNbjuoRdQ==", - "dev": true, - "requires": { - "any-observable": "^0.3.0" - } - }, "@types/node": { - "version": "12.12.50", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.50.tgz", - "integrity": "sha512-5ImO01Fb8YsEOYpV+aeyGYztcYcjGsBvN4D7G5r1ef2cuQOpymjWNQi5V0rKHE6PC2ru3HkoUr/Br2/8GUA84w==", + "version": "14.17.32", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.32.tgz", + "integrity": "sha512-JcII3D5/OapPGx+eJ+Ik1SQGyt6WvuqdRfh9jUwL6/iHGjmyOriBDciBUu7lEIBTL2ijxwrR70WUnw5AEDmFvQ==", "dev": true }, "@types/sinonjs__fake-timers": { @@ -2980,6 +95,16 @@ "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", "dev": true }, + "@types/yauzl": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", + "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", + "dev": true, + "optional": true, + "requires": { + "@types/node": "*" + } + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -3010,16 +135,25 @@ "uri-js": "^4.2.2" } }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { @@ -3031,12 +165,6 @@ "color-convert": "^2.0.1" } }, - "any-observable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", - "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", - "dev": true - }, "arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", @@ -3064,6 +192,12 @@ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, "async": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/async/-/async-3.2.1.tgz", @@ -3146,12 +280,6 @@ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", "dev": true }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, "cachedir": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", @@ -3178,6 +306,17 @@ "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "check-more-types": { @@ -3187,9 +326,9 @@ "dev": true }, "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", "dev": true }, "clean-stack": { @@ -3199,12 +338,12 @@ "dev": true }, "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, "requires": { - "restore-cursor": "^1.0.1" + "restore-cursor": "^3.1.0" } }, "cli-table3": { @@ -3219,43 +358,15 @@ } }, "cli-truncate": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", - "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", "dev": true, "requires": { - "slice-ansi": "0.0.4", - "string-width": "^1.0.1" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" } }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3271,6 +382,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "dev": true + }, "colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", @@ -3304,22 +421,10 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, "cross-env": { @@ -3349,47 +454,48 @@ "dev": true }, "cypress": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-6.9.1.tgz", - "integrity": "sha512-/RVx6sOhsyTR9sd9v0BHI4tnDZAhsH9rNat7CIKCUEr5VPWxyfGH0EzK4IHhAqAH8vjFcD4U14tPiJXshoUrmQ==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-8.4.1.tgz", + "integrity": "sha512-itJXq0Vx3sXCUrDyBi2IUrkxVu/gTTp1VhjB5tzGgkeCR8Ae+/T8WV63rsZ7fS8Tpq7LPPXiyoM/sEdOX7cR6A==", "dev": true, "requires": { - "@cypress/listr-verbose-renderer": "^0.4.1", - "@cypress/request": "^2.88.5", + "@cypress/request": "^2.88.6", "@cypress/xvfb": "^1.2.4", - "@types/node": "12.12.50", - "@types/sinonjs__fake-timers": "^6.0.1", + "@types/node": "^14.14.31", + "@types/sinonjs__fake-timers": "^6.0.2", "@types/sizzle": "^2.3.2", - "arch": "^2.1.2", - "blob-util": "2.0.2", + "arch": "^2.2.0", + "blob-util": "^2.0.2", "bluebird": "^3.7.2", "cachedir": "^2.3.0", "chalk": "^4.1.0", "check-more-types": "^2.24.0", + "cli-cursor": "^3.1.0", "cli-table3": "~0.6.0", "commander": "^5.1.0", "common-tags": "^1.8.0", - "dayjs": "^1.9.3", - "debug": "4.3.2", - "eventemitter2": "^6.4.2", - "execa": "^4.0.2", + "dayjs": "^1.10.4", + "debug": "^4.3.2", + "enquirer": "^2.3.6", + "eventemitter2": "^6.4.3", + "execa": "4.1.0", "executable": "^4.1.1", - "extract-zip": "^1.7.0", - "fs-extra": "^9.0.1", + "extract-zip": "2.0.1", + "figures": "^3.2.0", + "fs-extra": "^9.1.0", "getos": "^3.2.1", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.3.2", + "is-ci": "^3.0.0", + "is-installed-globally": "~0.4.0", "lazy-ass": "^1.6.0", - "listr": "^0.14.3", - "lodash": "^4.17.19", + "listr2": "^3.8.3", + "lodash": "^4.17.21", "log-symbols": "^4.0.0", "minimist": "^1.2.5", - "moment": "^2.29.1", "ospath": "^1.2.2", - "pretty-bytes": "^5.4.1", + "pretty-bytes": "^5.6.0", "ramda": "~0.27.1", "request-progress": "^3.0.0", - "supports-color": "^7.2.0", + "supports-color": "^8.1.1", "tmp": "~0.2.1", "untildify": "^4.0.0", "url": "^0.11.0", @@ -3405,12 +511,6 @@ "assert-plus": "^1.0.0" } }, - "date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", - "dev": true - }, "dayjs": { "version": "1.10.7", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", @@ -3424,6 +524,14 @@ "dev": true, "requires": { "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, "del": { @@ -3467,12 +575,6 @@ "safer-buffer": "^2.1.0" } }, - "elegant-spinner": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", - "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", - "dev": true - }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -3488,6 +590,15 @@ "once": "^1.4.0" } }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -3526,12 +637,6 @@ "pify": "^2.2.0" } }, - "exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", - "dev": true - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -3539,32 +644,15 @@ "dev": true }, "extract-zip": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", - "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "dev": true, "requires": { - "concat-stream": "^1.6.2", - "debug": "^2.6.9", - "mkdirp": "^0.5.4", + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", "yauzl": "^2.10.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } } }, "extsprintf": { @@ -3629,13 +717,12 @@ } }, "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" + "escape-string-regexp": "^1.0.5" } }, "fill-range": { @@ -3733,12 +820,12 @@ } }, "global-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", - "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", "dev": true, "requires": { - "ini": "1.3.7" + "ini": "2.0.0" } }, "globby": { @@ -3777,15 +864,6 @@ "har-schema": "^2.0.0" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -3815,12 +893,6 @@ "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", "dev": true }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3838,18 +910,18 @@ "dev": true }, "ini": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", - "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", "dev": true }, "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", "dev": true, "requires": { - "ci-info": "^2.0.0" + "ci-info": "^3.2.0" } }, "is-extglob": { @@ -3874,13 +946,13 @@ } }, "is-installed-globally": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", - "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", "dev": true, "requires": { - "global-dirs": "^2.0.1", - "is-path-inside": "^3.0.1" + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" } }, "is-number": { @@ -3889,15 +961,6 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "is-observable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", - "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", - "dev": true, - "requires": { - "symbol-observable": "^1.1.0" - } - }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -3910,12 +973,6 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, - "is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true - }, "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -3934,12 +991,6 @@ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -4004,200 +1055,19 @@ "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", "dev": true }, - "listr": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", - "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", - "dev": true, - "requires": { - "@samverschueren/stream-to-observable": "^0.3.0", - "is-observable": "^1.1.0", - "is-promise": "^2.1.0", - "is-stream": "^1.1.0", - "listr-silent-renderer": "^1.1.1", - "listr-update-renderer": "^0.5.0", - "listr-verbose-renderer": "^0.5.0", - "p-map": "^2.0.0", - "rxjs": "^6.3.3" - }, - "dependencies": { - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true - } - } - }, - "listr-silent-renderer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", - "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", - "dev": true - }, - "listr-update-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", - "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^2.3.0", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "dev": true, - "requires": { - "chalk": "^1.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "listr-verbose-renderer": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", - "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", + "listr2": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.13.1.tgz", + "integrity": "sha512-pk4YBDA2cxtpM8iLHbz6oEsfZieJKHf6Pt19NlKaHZZVpqHyVs/Wqr7RfBBCeAFCJchGO7WQHVkUPZTvJMHk8w==", "dev": true, "requires": { - "chalk": "^2.4.1", - "cli-cursor": "^2.1.0", - "date-fns": "^1.27.2", - "figures": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rxjs": "^6.6.7", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" } }, "lodash": { @@ -4223,48 +1093,37 @@ } }, "log-update": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", - "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", "dev": true, "requires": { - "ansi-escapes": "^3.0.0", - "cli-cursor": "^2.0.0", - "wrap-ansi": "^3.0.1" + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" }, "dependencies": { - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" } }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } } } @@ -4327,25 +1186,10 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", - "dev": true - }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "mute-stream": { @@ -4369,12 +1213,6 @@ "path-key": "^3.0.0" } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -4462,12 +1300,6 @@ "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", "dev": true }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, "prompt": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/prompt/-/prompt-1.2.0.tgz", @@ -4544,29 +1376,6 @@ "mute-stream": "~0.0.4" } }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } - }, "request-progress": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", @@ -4577,21 +1386,13 @@ } }, "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - }, - "dependencies": { - "onetime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true - } + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" } }, "reusify": { @@ -4673,10 +1474,15 @@ "dev": true }, "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } }, "sshpk": { "version": "1.16.1", @@ -4701,23 +1507,6 @@ "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", "dev": true }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } - }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -4727,32 +1516,15 @@ "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } } }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^5.0.1" } }, "strip-final-newline": { @@ -4762,26 +1534,26 @@ "dev": true }, "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { "has-flag": "^4.0.0" } }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true - }, "throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", "dev": true }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, "tmp": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", @@ -4831,10 +1603,10 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true }, "typescript": { @@ -4891,12 +1663,6 @@ } } }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -4912,14 +1678,6 @@ "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - } } }, "which": { @@ -4960,46 +1718,14 @@ } }, "wrap-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", - "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } }, "wrappy": { diff --git a/tests/Umbraco.Tests.AcceptanceTest/package.json b/tests/Umbraco.Tests.AcceptanceTest/package.json index 34c9469eab2e..fd401c72c0cd 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package.json @@ -9,7 +9,7 @@ }, "devDependencies": { "cross-env": "^7.0.2", - "cypress": "^6.8.0", + "cypress": "8.4.1", "del": "^6.0.0", "ncp": "^2.0.0", "prompt": "^1.2.0", diff --git a/tests/Umbraco.Tests.Common/Builders/ContentBuilder.cs b/tests/Umbraco.Tests.Common/Builders/ContentBuilder.cs index 452141135213..cb281523388e 100644 --- a/tests/Umbraco.Tests.Common/Builders/ContentBuilder.cs +++ b/tests/Umbraco.Tests.Common/Builders/ContentBuilder.cs @@ -72,7 +72,7 @@ public ContentBuilder WithParent(IContent parent) public ContentBuilder WithContentType(IContentType contentType) { _contentTypeBuilder = null; - _contentType = contentType; + _contentType = contentType; return this; } @@ -172,6 +172,11 @@ public override Content Build() content.SortOrder = sortOrder; content.Trashed = trashed; + if (contentType.DefaultTemplate?.Id > 0) + { + content.TemplateId = contentType.DefaultTemplate.Id; + } + foreach (KeyValuePair cultureName in _cultureNames) { content.SetCultureName(cultureName.Value, cultureName.Key); diff --git a/tests/Umbraco.Tests.Common/Builders/ContentDataBuilder.cs b/tests/Umbraco.Tests.Common/Builders/ContentDataBuilder.cs new file mode 100644 index 000000000000..596d64dd3c5f --- /dev/null +++ b/tests/Umbraco.Tests.Common/Builders/ContentDataBuilder.cs @@ -0,0 +1,221 @@ +using System; +using System.Collections.Generic; +using Umbraco.Extensions; +using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; +using Umbraco.Cms.Tests.Common.Builders.Extensions; +using Umbraco.Cms.Tests.Common.Builders.Interfaces; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Strings; +using Umbraco.Cms.Core.PropertyEditors; +using Moq; +using Umbraco.Cms.Infrastructure.Serialization; +using System.Linq; + +namespace Umbraco.Cms.Tests.Common.Builders +{ + + public class ContentDataBuilder : BuilderBase, IWithNameBuilder + { + private string _name; + private DateTime? _now; + private string _segment; + private int? _versionId; + private int? _writerId; + private int? _templateId; + private bool? _published; + private Dictionary _properties; + private Dictionary _cultureInfos; + + string IWithNameBuilder.Name + { + get => _name; + set => _name = value; + } + + public ContentDataBuilder WithVersionDate(DateTime now) + { + _now = now; + return this; + } + + public ContentDataBuilder WithUrlSegment(string segment) + { + _segment = segment; + return this; + } + + public ContentDataBuilder WithVersionId(int versionId) + { + _versionId = versionId; + return this; + } + + public ContentDataBuilder WithWriterId(int writerId) + { + _writerId = writerId; + return this; + } + + public ContentDataBuilder WithTemplateId(int templateId) + { + _templateId = templateId; + return this; + } + + public ContentDataBuilder WithPublished(bool published) + { + _published = published; + return this; + } + + public ContentDataBuilder WithProperties(Dictionary properties) + { + _properties = properties; + return this; + } + + public ContentDataBuilder WithCultureInfos(Dictionary cultureInfos) + { + _cultureInfos = cultureInfos; + return this; + } + + /// + /// Build and dynamically update an existing content type + /// + /// + /// + /// + /// + /// + /// Will configure the content type with this alias/name if supplied when it's not already set on the content type. + /// + /// + /// + public ContentData Build( + IShortStringHelper shortStringHelper, + Dictionary propertyDataTypes, + TContentType contentType, + string contentTypeAlias = null, + bool autoCreateCultureNames = false) where TContentType : class, IContentTypeComposition + { + if (_name.IsNullOrWhiteSpace()) + { + throw new InvalidOperationException("Cannot build without a name"); + } + _segment ??= _name.ToLower().ReplaceNonAlphanumericChars('-'); + + // create or copy the current culture infos for the content + Dictionary contentCultureInfos = _cultureInfos == null + ? new Dictionary() + : new Dictionary(_cultureInfos); + + contentType.Alias ??= contentTypeAlias; + contentType.Name ??= contentTypeAlias; + contentType.Key = contentType.Key == default ? Guid.NewGuid() : contentType.Key; + contentType.Id = contentType.Id == default ? Math.Abs(contentTypeAlias.GetHashCode()) : contentType.Id; + + if (_properties == null) + { + _properties = new Dictionary(); + } + + foreach (KeyValuePair prop in _properties) + { + //var dataType = new DataType(new VoidEditor("Label", Mock.Of()), new ConfigurationEditorJsonSerializer()) + //{ + // Id = 4 + //}; + + if (!propertyDataTypes.TryGetValue(prop.Key, out IDataType dataType)) + { + dataType = propertyDataTypes.First().Value; + } + + var propertyType = new PropertyType(shortStringHelper, dataType, prop.Key); + + // check each property for culture and set variations accordingly, + // this will also ensure that we have the correct culture name on the content + // set for each culture too. + foreach (PropertyData cultureValue in prop.Value.Where(x => !x.Culture.IsNullOrWhiteSpace())) + { + // set the property type to vary based on the values + propertyType.Variations |= ContentVariation.Culture; + + // if there isn't already a culture, then add one with the default name + if (autoCreateCultureNames && !contentCultureInfos.TryGetValue(cultureValue.Culture, out CultureVariation cultureVariation)) + { + cultureVariation = new CultureVariation + { + Date = DateTime.Now, + IsDraft = true, + Name = _name, + UrlSegment = _segment + }; + contentCultureInfos[cultureValue.Culture] = cultureVariation; + } + } + + // set variations for segments if there is any + if (prop.Value.Any(x => !x.Segment.IsNullOrWhiteSpace())) + { + propertyType.Variations |= ContentVariation.Segment; + contentType.Variations |= ContentVariation.Segment; + } + + if (!contentType.PropertyTypeExists(propertyType.Alias)) + { + contentType.AddPropertyType(propertyType); + } + } + + if (contentCultureInfos.Count > 0) + { + contentType.Variations |= ContentVariation.Culture; + WithCultureInfos(contentCultureInfos); + } + + var result = Build(); + return result; + } + + public override ContentData Build() + { + var now = _now ?? DateTime.Now; + var versionId = _versionId ?? 1; + var writerId = _writerId ?? -1; + var templateId = _templateId ?? 0; + var published = _published ?? true; + var properties = _properties ?? new Dictionary(); + var cultureInfos = _cultureInfos ?? new Dictionary(); + var segment = _segment ?? _name.ToLower().ReplaceNonAlphanumericChars('-'); + + var contentData = new ContentData( + _name, + segment, + versionId, + now, + writerId, + templateId, + published, + properties, + cultureInfos); + + return contentData; + } + + public static ContentData CreateBasic(string name, DateTime? versionDate = null) + => new ContentDataBuilder() + .WithName(name) + .WithVersionDate(versionDate ?? DateTime.Now) + .Build(); + + public static ContentData CreateVariant(string name, Dictionary cultureInfos, DateTime? versionDate = null, bool published = true) + => new ContentDataBuilder() + .WithName(name) + .WithVersionDate(versionDate ?? DateTime.Now) + .WithCultureInfos(cultureInfos) + .WithPublished(published) + .Build(); + } +} diff --git a/tests/Umbraco.Tests.Common/Builders/ContentNodeKitBuilder.cs b/tests/Umbraco.Tests.Common/Builders/ContentNodeKitBuilder.cs new file mode 100644 index 000000000000..f3314389ddfc --- /dev/null +++ b/tests/Umbraco.Tests.Common/Builders/ContentNodeKitBuilder.cs @@ -0,0 +1,96 @@ +using System; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; + +namespace Umbraco.Cms.Tests.Common.Builders +{ + public class ContentNodeKitBuilder : BuilderBase + { + private int _contentTypeId; + private ContentNode _contentNode; + private ContentData _draftData; + private ContentData _publishedData; + + public ContentNodeKitBuilder WithContentNode(ContentNode contentNode) + { + _contentNode = contentNode; + return this; + } + + public ContentNodeKitBuilder WithContentNode(int id, Guid uid, int level, string path, int sortOrder, int parentContentId, DateTime createDate, int creatorId) + { + _contentNode = new ContentNode(id, uid, level, path, sortOrder, parentContentId, createDate, creatorId); + return this; + } + + public ContentNodeKitBuilder WithContentTypeId(int contentTypeId) + { + _contentTypeId = contentTypeId; + return this; + } + + public ContentNodeKitBuilder WithDraftData(ContentData draftData) + { + _draftData = draftData; + return this; + } + + public ContentNodeKitBuilder WithPublishedData(ContentData publishedData) + { + _publishedData = publishedData; + return this; + } + + public override ContentNodeKit Build() + { + var data = new ContentNodeKit(_contentNode, _contentTypeId, _draftData, _publishedData); + return data; + } + + /// + /// Creates a ContentNodeKit + /// + /// + /// + /// + /// + /// + /// Optional. Will get calculated based on the path value if not specified. + /// + /// + /// Optional. Will get calculated based on the path value if not specified. + /// + /// + /// + /// + /// + /// + /// + public static ContentNodeKit CreateWithContent( + int contentTypeId, + int id, + string path, + int? sortOrder = null, + int? level = null, + int? parentContentId = null, + int creatorId = -1, + Guid? uid = null, + DateTime? createDate = null, + ContentData draftData = null, + ContentData publishedData = null) + { + var pathParts = path.Split(','); + if (pathParts.Length >= 2) + { + parentContentId ??= int.Parse(pathParts[^2]); + } + + return new ContentNodeKitBuilder() + .WithContentTypeId(contentTypeId) + .WithContentNode(id, uid ?? Guid.NewGuid(), level ?? pathParts.Length - 1, path, sortOrder ?? 0, parentContentId.Value, createDate ?? DateTime.Now, creatorId) + .WithDraftData(draftData) + .WithPublishedData(publishedData) + .Build(); + } + } +} diff --git a/tests/Umbraco.Tests.Common/Builders/Interfaces/IWithAllowAsRootBuilder.cs b/tests/Umbraco.Tests.Common/Builders/Interfaces/IWithAllowAsRootBuilder.cs new file mode 100644 index 000000000000..09148dc048b0 --- /dev/null +++ b/tests/Umbraco.Tests.Common/Builders/Interfaces/IWithAllowAsRootBuilder.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Cms.Tests.Common.Builders.Interfaces +{ + public interface IWithAllowAsRootBuilder + { + bool? AllowAsRoot { get; set; } + } +} diff --git a/tests/Umbraco.Tests.Common/Builders/PropertyDataBuilder.cs b/tests/Umbraco.Tests.Common/Builders/PropertyDataBuilder.cs new file mode 100644 index 000000000000..04cc32711a57 --- /dev/null +++ b/tests/Umbraco.Tests.Common/Builders/PropertyDataBuilder.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using Umbraco.Extensions; +using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; +using System.Linq; + +namespace Umbraco.Cms.Tests.Common.Builders +{ + public class PropertyDataBuilder : BuilderBase> + { + private readonly Dictionary> _properties = new(); + + public PropertyDataBuilder WithPropertyData(string alias, PropertyData propertyData) + { + if (!_properties.TryGetValue(alias, out List propertyDataCollection)) + { + propertyDataCollection = new List(); + _properties[alias] = propertyDataCollection; + } + + propertyDataCollection.Add(propertyData); + + return this; + } + + public PropertyDataBuilder WithPropertyData(string alias, object value, string culture = null, string segment = null) + => WithPropertyData(alias, new PropertyData + { + Culture = culture ?? string.Empty, + Segment = segment ?? string.Empty, + Value = value + }); + + public override Dictionary Build() + => _properties.ToDictionary(x => x.Key, x => x.Value.ToArray()); + } +} diff --git a/tests/Umbraco.Tests.Common/Published/PublishedContentXml.cs b/tests/Umbraco.Tests.Common/Published/PublishedContentXml.cs new file mode 100644 index 000000000000..f59445291e97 --- /dev/null +++ b/tests/Umbraco.Tests.Common/Published/PublishedContentXml.cs @@ -0,0 +1,152 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System; + +namespace Umbraco.Cms.Tests.Common.Published +{ + public static class PublishedContentXml + { + // The content XML that was used for the old PublishContentCacheTests + public static string PublishContentCacheTestsXml() + => @" + + +]> + + + + + + + + + + + + + + +"; + + // The content XML that was used in the old BaseWebTest class + public static string BaseWebTestXml(int templateId) + => @" + + + + +]> + + + + + 1 + + This is some content]]> + + + + + + + + + + + + + + + + + + +"; + + // The content XML that was used in the old TestWithDatabase class + public static string TestWithDatabaseXml(int templateId) + => @" + + + + +]> + + + + + 1 + + This is some content]]> + + + + + + + + + + + + + + + + +"; + + // The content XML that was used in the old PublishedContentTest class + public static string PublishedContentTestXml(int templateId, Guid node1173Guid) + => @" + + + + +]> + + + + + 1 + + + This is some content]]> + + + + + + + + + + 0 + + + 0 + + + 0 + + + + + 1 + + + + + + + + + +"; + } +} diff --git a/tests/Umbraco.Tests.Common/Published/PublishedContentXmlAdapter.cs b/tests/Umbraco.Tests.Common/Published/PublishedContentXmlAdapter.cs new file mode 100644 index 000000000000..d24be5ceb784 --- /dev/null +++ b/tests/Umbraco.Tests.Common/Published/PublishedContentXmlAdapter.cs @@ -0,0 +1,146 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.Collections.Generic; +using System.Xml.Linq; +using System.Xml.XPath; +using System.Linq; +using Umbraco.Extensions; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common.Builders; +using System; +using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; +using Umbraco.Cms.Tests.Common.Builders.Extensions; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Strings; +using Umbraco.Cms.Core.PropertyEditors; +using Moq; +using Umbraco.Cms.Infrastructure.Serialization; + +namespace Umbraco.Cms.Tests.Common.Published +{ + /// + /// Converts legacy Umbraco XML structures to NuCache collections + /// to populate a test implementation of + /// + /// + /// This does not support variant data because the XML structure doesn't support variant data. + /// + public static class PublishedContentXmlAdapter + { + /// + /// Generate a collection of based on legacy umbraco XML + /// + /// The legacy umbraco XML + /// + /// Dynamically generates a list of s based on the XML data + /// Dynamically generates a list of for tests + /// + public static IEnumerable GetContentNodeKits( + string xml, + IShortStringHelper shortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes) + { + // use the label data type for all data for these tests except in the case + // where a property is named 'content', in which case use the RTE. + var serializer = new ConfigurationEditorJsonSerializer(); + var labelDataType = new DataType(new VoidEditor("Label", Mock.Of()), serializer) { Id = 3 }; + var rteDataType = new DataType(new VoidEditor("RTE", Mock.Of()), serializer) { Id = 4 }; + dataTypes = new[] { labelDataType, rteDataType }; + + var kitsAndXml = new List<(ContentNodeKit kit, XElement node)>(); + + var xDoc = XDocument.Parse(xml); + IEnumerable nodes = xDoc.XPathSelectElements("//*[@isDoc]"); + foreach (XElement node in nodes) + { + var id = node.AttributeValue("id"); + Guid key = node.AttributeValue("key") ?? id.ToGuid(); + + var propertyElements = node.Elements().Where(x => x.Attribute("id") == null); + var properties = new Dictionary(); + foreach(XElement propertyElement in propertyElements) + { + properties[propertyElement.Name.LocalName] = new[] + { + // TODO: builder? + new PropertyData + { + Culture = string.Empty, + Segment = string.Empty, + Value = propertyElement.Value + } + }; + } + + var contentData = new ContentDataBuilder() + .WithName(node.AttributeValue("nodeName")) + .WithProperties(properties) + .WithPublished(true) + .WithTemplateId(node.AttributeValue("template")) + .WithUrlSegment(node.AttributeValue("urlName")) + .WithVersionDate(node.AttributeValue("updateDate")) + .WithWriterId(node.AttributeValue("writerID")) + .Build(); + + ContentNodeKit kit = ContentNodeKitBuilder.CreateWithContent( + node.AttributeValue("nodeType"), + id, + node.AttributeValue("path"), + node.AttributeValue("sortOrder"), + node.AttributeValue("level"), + node.AttributeValue("parentID"), + node.AttributeValue("creatorID"), + key, + node.AttributeValue("createDate"), + contentData, + contentData); + + kitsAndXml.Add((kit, node)); + } + + // put together the unique content types + var contentTypesIdToType = new Dictionary(); + foreach((ContentNodeKit kit, XElement node) in kitsAndXml) + { + if (!contentTypesIdToType.TryGetValue(kit.ContentTypeId, out ContentType contentType)) + { + contentType = new ContentType(shortStringHelper, -1) + { + Id = kit.ContentTypeId, + Alias = node.Name.LocalName + }; + SetContentTypeProperties(shortStringHelper, labelDataType, rteDataType, kit, contentType); + contentTypesIdToType[kit.ContentTypeId] = contentType; + } + else + { + // we've already created it but might need to add properties + SetContentTypeProperties(shortStringHelper, labelDataType, rteDataType, kit, contentType); + } + } + + contentTypes = contentTypesIdToType.Values.ToArray(); + + return kitsAndXml.Select(x => x.kit); + } + + private static void SetContentTypeProperties(IShortStringHelper shortStringHelper, DataType labelDataType, DataType rteDataType, ContentNodeKit kit, ContentType contentType) + { + foreach (KeyValuePair property in kit.DraftData.Properties) + { + var propertyType = new PropertyType(shortStringHelper, labelDataType, property.Key); + + if (!contentType.PropertyTypeExists(propertyType.Alias)) + { + if (propertyType.Alias == "content") + { + propertyType.DataTypeId = rteDataType.Id; + } + contentType.AddPropertyType(propertyType); + } + } + } + } +} diff --git a/tests/Umbraco.Tests.Common/Published/PublishedSnapshotTestObjects.cs b/tests/Umbraco.Tests.Common/Published/PublishedSnapshotTestObjects.cs index 16eb4adda07b..764f646ad8be 100644 --- a/tests/Umbraco.Tests.Common/Published/PublishedSnapshotTestObjects.cs +++ b/tests/Umbraco.Tests.Common/Published/PublishedSnapshotTestObjects.cs @@ -8,6 +8,7 @@ namespace Umbraco.Cms.Tests.Common.Published { + public class PublishedSnapshotTestObjects { [PublishedModel("element1")] diff --git a/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/AutoPublishedContentType.cs b/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/AutoPublishedContentType.cs deleted file mode 100644 index b36f7e90d130..000000000000 --- a/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/AutoPublishedContentType.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using System; -using System.Collections.Generic; -using System.Linq; -using Moq; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Infrastructure.Serialization; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Tests.Common.TestHelpers.PublishedContent -{ - - public class AutoPublishedContentType : PublishedContentType - { - private static readonly IPublishedPropertyType Default; - - static AutoPublishedContentType() - { - var configurationEditorJsonSerializer = new ConfigurationEditorJsonSerializer(); - var jsonSerializer = new JsonNetSerializer(); - var dataTypeServiceMock = new Mock(); - - var dataType = new DataType( - new VoidEditor( - Mock.Of()), - configurationEditorJsonSerializer) - { - Id = 666 - }; - dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); - - var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(() => Enumerable.Empty()), dataTypeServiceMock.Object); - Default = factory.CreatePropertyType("*", 666); - } - - public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable propertyTypes) - : base(key, id, alias, PublishedItemType.Content, Enumerable.Empty(), propertyTypes, ContentVariation.Nothing) - { - } - - public AutoPublishedContentType(Guid key, int id, string alias, Func> propertyTypes) - : base(key, id, alias, PublishedItemType.Content, Enumerable.Empty(), propertyTypes, ContentVariation.Nothing) - { - } - - public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable compositionAliases, IEnumerable propertyTypes) - : base(key, id, alias, PublishedItemType.Content, compositionAliases, propertyTypes, ContentVariation.Nothing) - { - } - - public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable compositionAliases, Func> propertyTypes) - : base(key, id, alias, PublishedItemType.Content, compositionAliases, propertyTypes, ContentVariation.Nothing) - { - } - - public override IPublishedPropertyType GetPropertyType(string alias) - { - IPublishedPropertyType propertyType = base.GetPropertyType(alias); - return propertyType ?? Default; - } - } -} diff --git a/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/ContentType2.cs b/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/ContentType2.cs deleted file mode 100644 index 37d2bb6949ee..000000000000 --- a/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/ContentType2.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Moq; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Tests.Common.TestHelpers.PublishedContent -{ - [PublishedModel("ContentType2")] - public class ContentType2 : PublishedContentModel - { - public ContentType2(IPublishedContent content, IPublishedValueFallback fallback) - : base(content, fallback) - { - } - - public int Prop1 => this.Value(Mock.Of(), "prop1"); - } -} diff --git a/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/ContentType2Sub.cs b/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/ContentType2Sub.cs deleted file mode 100644 index 0e2d6f9f168f..000000000000 --- a/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/ContentType2Sub.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Umbraco.Cms.Core.Models.PublishedContent; - -namespace Umbraco.Cms.Tests.Common.TestHelpers.PublishedContent -{ - [PublishedModel("ContentType2Sub")] - public class ContentType2Sub : ContentType2 - { - public ContentType2Sub(IPublishedContent content, IPublishedValueFallback fallback) - : base(content, fallback) - { - } - } -} diff --git a/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/InternalPublishedPropertyWithLanguageVariants.cs b/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/InternalPublishedPropertyWithLanguageVariants.cs deleted file mode 100644 index 842cba60619e..000000000000 --- a/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/InternalPublishedPropertyWithLanguageVariants.cs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using System.Collections.Generic; -using Umbraco.Cms.Core.PublishedCache.Internal; - -namespace Umbraco.Cms.Tests.Common.TestHelpers.PublishedContent -{ - public class InternalPublishedPropertyWithLanguageVariants : InternalPublishedProperty - { - private readonly IDictionary _solidSourceValues = new Dictionary(); - private readonly IDictionary _solidValues = new Dictionary(); - private readonly IDictionary _solidXPathValues = new Dictionary(); - - public override object GetSourceValue(string culture = null, string segment = null) - { - if (string.IsNullOrEmpty(culture)) - { - return base.GetSourceValue(culture, segment); - } - - return _solidSourceValues.ContainsKey(culture) ? _solidSourceValues[culture] : null; - } - - public override object GetValue(string culture = null, string segment = null) - { - if (string.IsNullOrEmpty(culture)) - { - return base.GetValue(culture, segment); - } - - return _solidValues.ContainsKey(culture) ? _solidValues[culture] : null; - } - - public override object GetXPathValue(string culture = null, string segment = null) - { - if (string.IsNullOrEmpty(culture)) - { - return base.GetXPathValue(culture, segment); - } - - return _solidXPathValues.ContainsKey(culture) ? _solidXPathValues[culture] : null; - } - - public override bool HasValue(string culture = null, string segment = null) - { - if (string.IsNullOrEmpty(culture)) - { - return base.HasValue(culture, segment); - } - - return _solidSourceValues.ContainsKey(culture); - } - - public void SetSourceValue(string culture, object value, bool defaultValue = false) - { - _solidSourceValues.Add(culture, value); - if (defaultValue) - { - SolidSourceValue = value; - SolidHasValue = true; - } - } - - public void SetValue(string culture, object value, bool defaultValue = false) - { - _solidValues.Add(culture, value); - if (defaultValue) - { - SolidValue = value; - SolidHasValue = true; - } - } - - public void SetXPathValue(string culture, object value, bool defaultValue = false) - { - _solidXPathValues.Add(culture, value); - if (defaultValue) - { - SolidXPathValue = value; - } - } - } -} diff --git a/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/PublishedContentStrong1.cs b/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/PublishedContentStrong1.cs deleted file mode 100644 index 8c2d501d3e6f..000000000000 --- a/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/PublishedContentStrong1.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Moq; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Tests.Common.TestHelpers.PublishedContent -{ - public class PublishedContentStrong1 : PublishedContentModel - { - public PublishedContentStrong1(IPublishedContent content, IPublishedValueFallback fallback) - : base(content, fallback) - { - } - - public int StrongValue => this.Value(Mock.Of(), "strongValue"); - } -} diff --git a/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/PublishedContentStrong1Sub.cs b/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/PublishedContentStrong1Sub.cs deleted file mode 100644 index 96748b413652..000000000000 --- a/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/PublishedContentStrong1Sub.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Moq; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Tests.Common.TestHelpers.PublishedContent -{ - public class PublishedContentStrong1Sub : PublishedContentStrong1 - { - public PublishedContentStrong1Sub(IPublishedContent content, IPublishedValueFallback fallback) - : base(content, fallback) - { - } - - public int AnotherValue => this.Value(Mock.Of(), "anotherValue"); - } -} diff --git a/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/PublishedContentStrong2.cs b/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/PublishedContentStrong2.cs deleted file mode 100644 index 0b88c56eaa27..000000000000 --- a/tests/Umbraco.Tests.Common/TestHelpers/PublishedContent/PublishedContentStrong2.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Moq; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Tests.Common.TestHelpers.PublishedContent -{ - public class PublishedContentStrong2 : PublishedContentModel - { - public PublishedContentStrong2(IPublishedContent content, IPublishedValueFallback fallback) - : base(content, fallback) - { - } - - public int StrongValue => this.Value(Mock.Of(), "strongValue"); - } -} diff --git a/tests/Umbraco.Tests.Common/TestLastChanceFinder.cs b/tests/Umbraco.Tests.Common/TestLastChanceFinder.cs new file mode 100644 index 000000000000..6a3c2e956a82 --- /dev/null +++ b/tests/Umbraco.Tests.Common/TestLastChanceFinder.cs @@ -0,0 +1,12 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Umbraco.Cms.Core.Routing; + +namespace Umbraco.Cms.Tests.Common +{ + public class TestLastChanceFinder : IContentLastChanceFinder + { + public bool TryFindContent(IPublishedRequestBuilder frequest) => false; + } +} diff --git a/tests/Umbraco.Tests.Common/TestPublishedSnapshotAccessor.cs b/tests/Umbraco.Tests.Common/TestPublishedSnapshotAccessor.cs index 400a79292e48..de6ed7b0b6ba 100644 --- a/tests/Umbraco.Tests.Common/TestPublishedSnapshotAccessor.cs +++ b/tests/Umbraco.Tests.Common/TestPublishedSnapshotAccessor.cs @@ -7,10 +7,14 @@ namespace Umbraco.Cms.Tests.Common { public class TestPublishedSnapshotAccessor : IPublishedSnapshotAccessor { + private IPublishedSnapshot _snapshot = null; + public bool TryGetPublishedSnapshot(out IPublishedSnapshot publishedSnapshot) { - publishedSnapshot = null; - return false; + publishedSnapshot = _snapshot; + return _snapshot != null; } + + public void SetCurrent(IPublishedSnapshot snapshot) => _snapshot = snapshot; } } diff --git a/tests/Umbraco.Tests.Common/Testing/TestOptionAttributeBase.cs b/tests/Umbraco.Tests.Common/Testing/TestOptionAttributeBase.cs index 1e62f1827c28..a5a4c2ff410a 100644 --- a/tests/Umbraco.Tests.Common/Testing/TestOptionAttributeBase.cs +++ b/tests/Umbraco.Tests.Common/Testing/TestOptionAttributeBase.cs @@ -6,12 +6,14 @@ using System.Linq; using System.Reflection; using NUnit.Framework; +using NUnit.Framework.Internal; using Umbraco.Cms.Core.Exceptions; namespace Umbraco.Cms.Tests.Common.Testing { public abstract class TestOptionAttributeBase : Attribute { + [Obsolete("This is not used anymore - Test classes are found using nunit helpers")] public static readonly List ScanAssemblies = new List(); public static TOptions GetTestOptions(MethodInfo method) @@ -29,26 +31,8 @@ public static TOptions GetTestOptions() where TOptions : TestOptionAttributeBase, new() { TestContext.TestAdapter test = TestContext.CurrentContext.Test; - var typeName = test.ClassName; var methodName = test.MethodName; - - // This will only get types from whatever is already loaded in the app domain. - var type = Type.GetType(typeName, false); - if (type == null) - { - // automatically add the executing and calling assemblies to the list to scan for this type - var scanAssemblies = ScanAssemblies.Union(new[] { Assembly.GetExecutingAssembly(), Assembly.GetCallingAssembly() }).ToList(); - - type = scanAssemblies - .Select(assembly => assembly.GetType(typeName, false)) - .FirstOrDefault(x => x != null); - if (type == null) - { - throw new PanicException($"Could not resolve the running test fixture from type name {typeName}.\n" + - $"To use base classes from Umbraco.Tests, add your test assembly to TestOptionAttributeBase.ScanAssemblies"); - } - } - + var type = TestExecutionContext.CurrentContext.TestObject.GetType(); MethodInfo methodInfo = type.GetMethod(methodName); // what about overloads? TOptions options = GetTestOptions(methodInfo); return options; diff --git a/tests/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/tests/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index 86f6a03216f3..2d140e433687 100644 --- a/tests/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/tests/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -4,6 +4,7 @@ using System; using System.Linq.Expressions; using System.Net.Http; +using System.Reflection; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -24,7 +25,6 @@ using Umbraco.Cms.Tests.Integration.Testing; using Umbraco.Cms.Web.BackOffice.Controllers; using Umbraco.Cms.Web.Common.Controllers; -using Umbraco.Cms.Web.UI; using Umbraco.Cms.Web.Website.Controllers; using Umbraco.Extensions; @@ -52,17 +52,22 @@ public override void Setup() * * See https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests */ - var factory = new UmbracoWebApplicationFactory(CreateHostBuilder, BeforeHostStart); + var factory = new UmbracoWebApplicationFactory(CreateHostBuilder, BeforeHostStart); // additional host configuration for web server integration tests Factory = factory.WithWebHostBuilder(builder => + { + // Otherwise inferred as $(SolutionDir)/Umbraco.Tests.Integration (note lack of src/tests) + builder.UseContentRoot(Assembly.GetExecutingAssembly().GetRootDirectorySafe()); // Executes after the standard ConfigureServices method builder.ConfigureTestServices(services => // Add a test auth scheme with a test auth handler to authn and assign the user services.AddAuthentication(TestAuthHandler.TestAuthenticationScheme) - .AddScheme(TestAuthHandler.TestAuthenticationScheme, options => { }))); + .AddScheme(TestAuthHandler.TestAuthenticationScheme, options => { })); + }); + Client = Factory.CreateClient(new WebApplicationFactoryClientOptions { @@ -141,7 +146,7 @@ protected string PrepareUrl(string url) protected LinkGenerator LinkGenerator { get; private set; } - protected WebApplicationFactory Factory { get; private set; } + protected WebApplicationFactory Factory { get; private set; } public override void ConfigureServices(IServiceCollection services) { diff --git a/tests/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs b/tests/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs index 3eef3c201f90..59ddfe55e80d 100644 --- a/tests/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs +++ b/tests/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Umbraco.Cms.Infrastructure.Persistence; @@ -118,13 +119,13 @@ public void Finish() string filename = Path.Combine(s_filesPath, DatabaseName).ToUpper(); - foreach (string database in s_localDbInstance.GetDatabases()) + Parallel.ForEach(s_localDbInstance.GetDatabases(), instance => { - if (database.StartsWith(filename)) + if (instance.StartsWith(filename)) { - s_localDbInstance.DropDatabase(database); + s_localDbInstance.DropDatabase(instance); } - } + }); _localDb.StopInstance(InstanceName); diff --git a/tests/Umbraco.Tests.Integration/Testing/SqlDeveloperTestDatabase.cs b/tests/Umbraco.Tests.Integration/Testing/SqlDeveloperTestDatabase.cs index 6192bacb728f..b35b6ac0d5e8 100644 --- a/tests/Umbraco.Tests.Integration/Testing/SqlDeveloperTestDatabase.cs +++ b/tests/Umbraco.Tests.Integration/Testing/SqlDeveloperTestDatabase.cs @@ -6,6 +6,7 @@ using System.Data.SqlClient; using System.Linq; using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Umbraco.Cms.Infrastructure.Persistence; @@ -118,10 +119,7 @@ public void Finish() { } - foreach (TestDbMeta testDatabase in _testDatabases) - { - Drop(testDatabase); - } + Parallel.ForEach(_testDatabases, Drop); } } } diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs index ad189cc02a86..5b033fcd4269 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs @@ -32,9 +32,8 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services { - /// - /// Tests covering all methods in the ContentService class. + /// Tests covering all methods in the ContentService class. /// [TestFixture] [UmbracoTest( @@ -43,6 +42,11 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services WithApplication = true)] public class ContentServiceTests : UmbracoIntegrationTestWithContent { + [SetUp] + public void Setup() => ContentRepositoryBase.ThrowOnWarning = true; + + [TearDown] + public void Teardown() => ContentRepositoryBase.ThrowOnWarning = false; // TODO: Add test to verify there is only ONE newest document/content in {Constants.DatabaseSchema.Tables.Document} table after updating. // TODO: Add test to delete specific version (with and without deleting prior versions) and versions by date. @@ -75,17 +79,11 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent private IValueEditorCache ValueEditorCache => GetRequiredService(); - [SetUp] - public void Setup() => ContentRepositoryBase.ThrowOnWarning = true; - protected override void CustomTestSetup(IUmbracoBuilder builder) => builder .AddNotificationHandler() .AddNotificationHandler() .AddNotificationHandler(); - [TearDown] - public void Teardown() => ContentRepositoryBase.ThrowOnWarning = false; - [Test] public void Create_Blueprint() { @@ -177,9 +175,10 @@ public void Get_All_Blueprints() FileService.SaveTemplate(ct2.DefaultTemplate); ContentTypeService.Save(ct2); - for (int i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { - Content blueprint = ContentBuilder.CreateTextpageContent(i % 2 == 0 ? ct1 : ct2, "hello" + i, Constants.System.Root); + Content blueprint = + ContentBuilder.CreateTextpageContent(i % 2 == 0 ? ct1 : ct2, "hello" + i, Constants.System.Root); ContentService.SaveBlueprint(blueprint); } @@ -218,7 +217,7 @@ public void Perform_Scheduled_Publishing() // 10x invariant content, half is scheduled to be published in 5 seconds, the other half is scheduled to be unpublished in 5 seconds var invariant = new List(); - for (int i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { Content c = ContentBuilder.CreateBasicContent(ctInvariant); c.Name = "name" + i; @@ -240,8 +239,8 @@ public void Perform_Scheduled_Publishing() // 10x variant content, half is scheduled to be published in 5 seconds, the other half is scheduled to be unpublished in 5 seconds var variant = new List(); - string alternatingCulture = langFr.IsoCode; - for (int i = 0; i < 10; i++) + var alternatingCulture = langFr.IsoCode; + for (var i = 0; i < 10; i++) { Content c = ContentBuilder.CreateBasicContent(ctVariant); c.SetCultureName("name-uk" + i, langUk.IsoCode); @@ -294,7 +293,7 @@ public void Perform_Scheduled_Publishing() // re-run the scheduled publishing, there should be no results runSched = ContentService.PerformScheduledPublish( - now.AddMinutes(1)).ToList(); + now.AddMinutes(1)).ToList(); Assert.AreEqual(0, runSched.Count); } @@ -305,10 +304,10 @@ public void Remove_Scheduled_Publishing_Date() // Arrange // Act - IContent content = ContentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); + IContent content = ContentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage"); content.ContentSchedule.Add(null, DateTime.Now.AddHours(2)); - ContentService.Save(content, Constants.Security.SuperUserId); + ContentService.Save(content); Assert.AreEqual(1, content.ContentSchedule.FullSchedule.Count); content = ContentService.GetById(content.Id); @@ -316,7 +315,7 @@ public void Remove_Scheduled_Publishing_Date() Assert.AreEqual(1, sched.Count); Assert.AreEqual(1, sched.Count(x => x.Culture == string.Empty)); content.ContentSchedule.Clear(ContentScheduleAction.Expire); - ContentService.Save(content, Constants.Security.SuperUserId); + ContentService.Save(content); // Assert content = ContentService.GetById(content.Id); @@ -330,8 +329,8 @@ public void Get_Top_Version_Ids() { // Arrange // Act - IContent content = ContentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); - for (int i = 0; i < 20; i++) + IContent content = ContentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage"); + for (var i = 0; i < 20; i++) { content.SetValue("bodyText", "hello world " + Guid.NewGuid()); ContentService.SaveAndPublish(content); @@ -351,12 +350,13 @@ public void Get_By_Ids_Sorted() // Arrange // Act var results = new List(); - for (int i = 0; i < 20; i++) + for (var i = 0; i < 20; i++) { results.Add(ContentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", 0)); } - IContent[] sortedGet = ContentService.GetByIds(new[] { results[10].Id, results[5].Id, results[12].Id }).ToArray(); + IContent[] sortedGet = ContentService.GetByIds(new[] { results[10].Id, results[5].Id, results[12].Id }) + .ToArray(); // Assert Assert.AreEqual(sortedGet[0].Id, results[10].Id); @@ -369,9 +369,9 @@ public void Count_All() { // Arrange // Act - for (int i = 0; i < 20; i++) + for (var i = 0; i < 20; i++) { - ContentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); + ContentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage"); } // Assert @@ -385,17 +385,18 @@ public void Count_By_Content_Type() Template template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("umbBlah", "test Doc Type", defaultTemplateId: template.Id); + ContentType contentType = + ContentTypeBuilder.CreateSimpleContentType("umbBlah", "test Doc Type", defaultTemplateId: template.Id); ContentTypeService.Save(contentType); // Act - for (int i = 0; i < 20; i++) + for (var i = 0; i < 20; i++) { - ContentService.CreateAndSave("Test", Constants.System.Root, "umbBlah", Constants.Security.SuperUserId); + ContentService.CreateAndSave("Test", Constants.System.Root, "umbBlah"); } // Assert - Assert.AreEqual(20, ContentService.Count(contentTypeAlias: "umbBlah")); + Assert.AreEqual(20, ContentService.Count("umbBlah")); } [Test] @@ -405,12 +406,13 @@ public void Count_Children() Template template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("umbBlah", "test Doc Type", defaultTemplateId: template.Id); + ContentType contentType = + ContentTypeBuilder.CreateSimpleContentType("umbBlah", "test Doc Type", defaultTemplateId: template.Id); ContentTypeService.Save(contentType); - IContent parent = ContentService.CreateAndSave("Test", Constants.System.Root, "umbBlah", Constants.Security.SuperUserId); + IContent parent = ContentService.CreateAndSave("Test", Constants.System.Root, "umbBlah"); // Act - for (int i = 0; i < 20; i++) + for (var i = 0; i < 20; i++) { ContentService.CreateAndSave("Test", parent, "umbBlah"); } @@ -426,13 +428,14 @@ public void Count_Descendants() Template template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("umbBlah", "test Doc Type", defaultTemplateId: template.Id); + ContentType contentType = + ContentTypeBuilder.CreateSimpleContentType("umbBlah", "test Doc Type", defaultTemplateId: template.Id); ContentTypeService.Save(contentType); - IContent parent = ContentService.CreateAndSave("Test", Constants.System.Root, "umbBlah", Constants.Security.SuperUserId); + IContent parent = ContentService.CreateAndSave("Test", Constants.System.Root, "umbBlah"); // Act IContent current = parent; - for (int i = 0; i < 20; i++) + for (var i = 0; i < 20; i++) { current = ContentService.CreateAndSave("Test", current, "umbBlah"); } @@ -458,7 +461,7 @@ public void Can_Remove_Property_Type() { // Arrange // Act - IContent content = ContentService.Create("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); + IContent content = ContentService.Create("Test", Constants.System.Root, "umbTextpage"); // Assert Assert.That(content, Is.Not.Null); @@ -470,7 +473,7 @@ public void Can_Create_Content() { // Arrange // Act - IContent content = ContentService.Create("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); + IContent content = ContentService.Create("Test", Constants.System.Root, "umbTextpage"); // Assert Assert.That(content, Is.Not.Null); @@ -486,7 +489,9 @@ public void Can_Create_Content_Without_Explicitly_Set_User() // Assert Assert.That(content, Is.Not.Null); Assert.That(content.HasIdentity, Is.False); - Assert.That(content.CreatorId, Is.EqualTo(Constants.Security.SuperUserId)); // Default to -1 aka SuperUser (unknown) since we didn't explicitly set this in the Create call + Assert.That(content.CreatorId, + Is.EqualTo(Constants.Security + .SuperUserId)); // Default to -1 aka SuperUser (unknown) since we didn't explicitly set this in the Create call } [Test] @@ -567,21 +572,21 @@ public void Can_Get_All_Versions_Of_Content() var versions = ContentService.GetVersions(Subpage.Id).ToList(); Assert.AreEqual(1, versions.Count); - int version1 = content.VersionId; + var version1 = content.VersionId; Console.WriteLine($"1 e={content.VersionId} p={content.PublishedVersionId}"); content.Name = "Text Page 2 Updated"; content.SetValue("author", "Jane Doe"); ContentService.SaveAndPublish(content); // publishes the current version, creates a version - int version2 = content.VersionId; + var version2 = content.VersionId; Console.WriteLine($"2 e={content.VersionId} p={content.PublishedVersionId}"); content.Name = "Text Page 2 ReUpdated"; content.SetValue("author", "Bob Hope"); ContentService.SaveAndPublish(content); // publishes again, creates a version - int version3 = content.VersionId; + var version3 = content.VersionId; Console.WriteLine($"3 e={content.VersionId} p={content.PublishedVersionId}"); IContent content1 = ContentService.GetById(content.Id); @@ -615,7 +620,8 @@ public void Can_Get_All_Versions_Of_Content() // and proper values // first, the current (edited) version, with edited and published versions Assert.AreEqual("John Farr", versions[0].GetValue("author")); // current version has the edited value - Assert.AreEqual("Bob Hope", versions[0].GetValue("author", published: true)); // and the published published value + Assert.AreEqual("Bob Hope", + versions[0].GetValue("author", published: true)); // and the published published value // then, the current (published) version, with edited == published Assert.AreEqual("Bob Hope", versions[1].GetValue("author")); // own edited version @@ -678,7 +684,7 @@ public void Can_Get_Content_In_RecycleBin() { // Arrange // Act - var contents = ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out long _).ToList(); + var contents = ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); // Assert Assert.That(contents, Is.Not.Null); @@ -706,7 +712,8 @@ public void Can_Unpublish_Content() [Test] public void Can_Unpublish_Content_Variation() { - IContent content = CreateEnglishAndFrenchDocument(out Language langUk, out Language langFr, out ContentType contentType); + IContent content = CreateEnglishAndFrenchDocument(out Language langUk, out Language langFr, + out ContentType contentType); content.PublishCulture(CultureImpact.Explicit(langFr.IsoCode, langFr.IsDefault)); content.PublishCulture(CultureImpact.Explicit(langUk.IsoCode, langUk.IsDefault)); @@ -738,7 +745,8 @@ public void Can_Unpublish_Content_Variation() [Test] public void Can_Publish_Culture_After_Last_Culture_Unpublished() { - IContent content = CreateEnglishAndFrenchDocument(out Language langUk, out Language langFr, out ContentType contentType); + IContent content = CreateEnglishAndFrenchDocument(out Language langUk, out Language langFr, + out ContentType contentType); PublishResult published = ContentService.SaveAndPublish(content, new[] { langFr.IsoCode, langUk.IsoCode }); Assert.AreEqual(PublishedState.Published, content.PublishedState); @@ -776,7 +784,8 @@ public void Can_Publish_Culture_After_Last_Culture_Unpublished() [Test] public void Unpublish_All_Cultures_Has_Unpublished_State() { - IContent content = CreateEnglishAndFrenchDocument(out Language langUk, out Language langFr, out ContentType contentType); + IContent content = CreateEnglishAndFrenchDocument(out Language langUk, out Language langFr, + out ContentType contentType); PublishResult published = ContentService.SaveAndPublish(content, new[] { langFr.IsoCode, langUk.IsoCode }); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); @@ -807,7 +816,8 @@ public void Unpublish_All_Cultures_Has_Unpublished_State() Assert.AreEqual(PublishResultType.SuccessUnpublishLastCulture, unpublished.Result); Assert.IsFalse(content.IsCulturePublished(langFr.IsoCode)); Assert.IsFalse(content.IsCulturePublished(langUk.IsoCode)); - Assert.AreEqual(PublishedState.Unpublished, content.PublishedState); // the last culture was unpublished so the document should also reflect this + Assert.AreEqual(PublishedState.Unpublished, + content.PublishedState); // the last culture was unpublished so the document should also reflect this // re-get content = ContentService.GetById(content.Id); @@ -859,7 +869,8 @@ public void Unpublishing_Mandatory_Language_Unpublishes_Document() [Test] public void Unpublishing_Already_Unpublished_Culture() { - IContent content = CreateEnglishAndFrenchDocument(out Language langUk, out Language langFr, out ContentType contentType); + IContent content = CreateEnglishAndFrenchDocument(out Language langUk, out Language langFr, + out ContentType contentType); PublishResult published = ContentService.SaveAndPublish(content, new[] { langFr.IsoCode, langUk.IsoCode }); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); @@ -894,7 +905,8 @@ public void Unpublishing_Already_Unpublished_Culture() [Test] public void Publishing_No_Cultures_Still_Saves() { - IContent content = CreateEnglishAndFrenchDocument(out Language langUk, out Language langFr, out ContentType contentType); + IContent content = CreateEnglishAndFrenchDocument(out Language langUk, out Language langFr, + out ContentType contentType); PublishResult published = ContentService.SaveAndPublish(content, new[] { langFr.IsoCode, langUk.IsoCode }); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); @@ -983,7 +995,7 @@ public void Can_Publish_Content_Variation_And_Detect_Changed_Cultures() // audit log will only show that french was published IAuditItem lastLog = AuditService.GetLogs(content.Id).Last(); - Assert.AreEqual($"Published languages: French (France)", lastLog.Comment); + Assert.AreEqual("Published languages: French (France)", lastLog.Comment); // re-get content = ContentService.GetById(content.Id); @@ -992,7 +1004,7 @@ public void Can_Publish_Content_Variation_And_Detect_Changed_Cultures() // audit log will only show that english was published lastLog = AuditService.GetLogs(content.Id).Last(); - Assert.AreEqual($"Published languages: English (United Kingdom)", lastLog.Comment); + Assert.AreEqual("Published languages: English (United Kingdom)", lastLog.Comment); } [Test] @@ -1027,7 +1039,7 @@ public void Can_Unpublish_Content_Variation_And_Detect_Changed_Cultures() // audit log will only show that french was unpublished IAuditItem lastLog = AuditService.GetLogs(content.Id).Last(); - Assert.AreEqual($"Unpublished languages: French (France)", lastLog.Comment); + Assert.AreEqual("Unpublished languages: French (France)", lastLog.Comment); // re-get content = ContentService.GetById(content.Id); @@ -1036,8 +1048,8 @@ public void Can_Unpublish_Content_Variation_And_Detect_Changed_Cultures() // audit log will only show that english was published var logs = AuditService.GetLogs(content.Id).ToList(); - Assert.AreEqual($"Unpublished languages: English (United Kingdom)", logs[^2].Comment); - Assert.AreEqual($"Unpublished (mandatory language unpublished)", logs[^1].Comment); + Assert.AreEqual("Unpublished languages: English (United Kingdom)", logs[^2].Comment); + Assert.AreEqual("Unpublished (mandatory language unpublished)", logs[^1].Comment); } [Test] @@ -1086,7 +1098,7 @@ public void IsPublishable() [Test] public void Can_Publish_Content_WithEvents() { - bool publishingWasCalled = false; + var publishingWasCalled = false; ContentNotificationHandler.PublishingContent = notification => { @@ -1109,7 +1121,8 @@ public void Can_Publish_Content_WithEvents() Assert.AreEqual("Home", content.Name); content.Name = "foo"; - PublishResult published = ContentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); + PublishResult published = + ContentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); Assert.That(published.Success, Is.True); Assert.That(content.Published, Is.True); @@ -1130,14 +1143,16 @@ public void Can_Not_Publish_Invalid_Cultures() { Content content = new ContentBuilder() .AddContentType() - .WithContentVariation(ContentVariation.Culture) - .Done() + .WithContentVariation(ContentVariation.Culture) + .Done() .Build(); Assert.Throws(() => ContentService.SaveAndPublish(content, new[] { "*" })); - Assert.Throws(() => ContentService.SaveAndPublish(content, new string[] { null })); + Assert.Throws( + () => ContentService.SaveAndPublish(content, new string[] { null })); Assert.Throws(() => ContentService.SaveAndPublish(content, new[] { "*", null })); - Assert.Throws(() => ContentService.SaveAndPublish(content, new[] { "en-US", "*", "es-ES" })); + Assert.Throws(() => + ContentService.SaveAndPublish(content, new[] { "en-US", "*", "es-ES" })); } [Test] @@ -1146,10 +1161,11 @@ public void Can_Publish_Only_Valid_Content() Template template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", + mandatoryProperties: true, defaultTemplateId: template.Id); ContentTypeService.Save(contentType); - int parentId = Textpage.Id; + var parentId = Textpage.Id; IContent parent = ContentService.GetById(parentId); @@ -1165,8 +1181,10 @@ public void Can_Publish_Only_Valid_Content() Assert.IsFalse(content.HasIdentity); // content cannot publish values because they are invalid - var propertyValidationService = new PropertyValidationService(PropertyEditorCollection, DataTypeService, TextService, ValueEditorCache); - bool isValid = propertyValidationService.IsPropertyDataValid(content, out IProperty[] invalidProperties, CultureImpact.Invariant); + var propertyValidationService = new PropertyValidationService(PropertyEditorCollection, DataTypeService, + TextService, ValueEditorCache); + var isValid = propertyValidationService.IsPropertyDataValid(content, out IProperty[] invalidProperties, + CultureImpact.Invariant); Assert.IsFalse(isValid); Assert.IsNotEmpty(invalidProperties); @@ -1204,7 +1222,7 @@ public void Can_Publish_And_Unpublish_Cultures_In_Single_Operation() content.SetCultureName("name-da", langDa.IsoCode); content.PublishCulture(CultureImpact.Explicit(langFr.IsoCode, langFr.IsDefault)); - PublishResult result = ((ContentService)ContentService).CommitDocumentChanges(content); + PublishResult result = ContentService.CommitDocumentChanges(content); Assert.IsTrue(result.Success); content = ContentService.GetById(content.Id); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); @@ -1213,7 +1231,7 @@ public void Can_Publish_And_Unpublish_Cultures_In_Single_Operation() content.UnpublishCulture(langFr.IsoCode); content.PublishCulture(CultureImpact.Explicit(langDa.IsoCode, langDa.IsDefault)); - result = ((ContentService)ContentService).CommitDocumentChanges(content); + result = ContentService.CommitDocumentChanges(content); Assert.IsTrue(result.Success); Assert.AreEqual(PublishResultType.SuccessMixedCulture, result.Result); @@ -1248,17 +1266,18 @@ private IEnumerable MapPublishValues(IEnumerable documents, [Test] public void Can_Publish_Content_Children() { - int parentId = Textpage.Id; + var parentId = Textpage.Id; IContent parent = ContentService.GetById(parentId); Console.WriteLine(" " + parent.Id); const int pageSize = 500; - int page = 0; - long total = long.MaxValue; + var page = 0; + var total = long.MaxValue; while (page * pageSize < total) { - IEnumerable descendants = ContentService.GetPagedDescendants(parent.Id, page++, pageSize, out total); + IEnumerable descendants = + ContentService.GetPagedDescendants(parent.Id, page++, pageSize, out total); foreach (IContent x in descendants) { Console.WriteLine(" ".Substring(0, x.Level) + x.Id); @@ -1274,14 +1293,17 @@ public void Can_Publish_Content_Children() foreach (PublishResult result in parentPublished) { - Console.WriteLine(" ".Substring(0, result.Content.Level) + $"{result.Content.Id}: {result.Result}"); + Console.WriteLine(" ".Substring(0, result.Content.Level) + + $"{result.Content.Id}: {result.Result}"); } // everything should be successful Assert.IsTrue(parentPublished.All(x => x.Success)); Assert.IsTrue(parent.Published); - IEnumerable children = ContentService.GetPagedChildren(parentId, 0, 500, out long totalChildren); // we only want the first so page size, etc.. is abitrary + IEnumerable + children = ContentService.GetPagedChildren(parentId, 0, 500, + out var totalChildren); // we only want the first so page size, etc.. is abitrary // children are published including ... that was released 5 mins ago Assert.IsTrue(children.First(x => x.Id == Subpage.Id).Published); @@ -1296,7 +1318,10 @@ public void Cannot_Publish_Expired_Content() ContentService.Save(content); IContent parent = ContentService.GetById(Textpage.Id); - PublishResult parentPublished = ContentService.SaveAndPublish(parent, userId: Constants.Security.SuperUserId); // Publish root Home node to enable publishing of 'Subpage.Id' + PublishResult parentPublished = + ContentService.SaveAndPublish(parent, + userId: Constants.Security + .SuperUserId); // Publish root Home node to enable publishing of 'Subpage.Id' // Act PublishResult published = ContentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); @@ -1320,7 +1345,7 @@ public void Cannot_Publish_Expired_Culture() content.ContentSchedule.Add("en-US", null, DateTime.Now.AddMinutes(-5)); ContentService.Save(content); - PublishResult published = ContentService.SaveAndPublish(content, "en-US", Constants.Security.SuperUserId); + PublishResult published = ContentService.SaveAndPublish(content, "en-US"); Assert.IsFalse(published.Success); Assert.AreEqual(PublishResultType.FailedPublishCultureHasExpired, published.Result); @@ -1333,10 +1358,13 @@ public void Cannot_Publish_Content_Awaiting_Release() // Arrange IContent content = ContentService.GetById(Subpage.Id); content.ContentSchedule.Add(DateTime.Now.AddHours(2), null); - ContentService.Save(content, Constants.Security.SuperUserId); + ContentService.Save(content); IContent parent = ContentService.GetById(Textpage.Id); - PublishResult parentPublished = ContentService.SaveAndPublish(parent, userId: Constants.Security.SuperUserId); // Publish root Home node to enable publishing of 'Subpage.Id' + PublishResult parentPublished = + ContentService.SaveAndPublish(parent, + userId: Constants.Security + .SuperUserId); // Publish root Home node to enable publishing of 'Subpage.Id' // Act PublishResult published = ContentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); @@ -1379,12 +1407,12 @@ public void Failed_Publish_Should_Not_Update_Edited_State_When_Edited_True() contentService.SaveAndPublish(content); - content.Properties[0].SetValue("Foo", culture: string.Empty); + content.Properties[0].SetValue("Foo", string.Empty); content.ContentSchedule.Add(DateTime.Now.AddHours(2), null); contentService.Save(content); // Act - var result = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); + PublishResult result = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); // Assert Assert.Multiple(() => @@ -1409,10 +1437,10 @@ public void Failed_Publish_Should_Not_Update_Edited_State_When_Edited_False() IContentType contentType = new ContentTypeBuilder() .WithId(0) .AddPropertyType() - .WithAlias("header") - .WithValueStorageType(ValueStorageType.Integer) - .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.TextBox) - .WithName("header") + .WithAlias("header") + .WithValueStorageType(ValueStorageType.Integer) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.TextBox) + .WithName("header") .Done() .WithContentVariation(ContentVariation.Nothing) .Build(); @@ -1434,7 +1462,7 @@ public void Failed_Publish_Should_Not_Update_Edited_State_When_Edited_False() contentService.Save(content); // Act - var result = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); + PublishResult result = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); // Assert Assert.Multiple(() => @@ -1461,7 +1489,7 @@ public void Cannot_Publish_Culture_Awaiting_Release() content.ContentSchedule.Add("en-US", DateTime.Now.AddHours(2), null); ContentService.Save(content); - PublishResult published = ContentService.SaveAndPublish(content, "en-US", Constants.Security.SuperUserId); + PublishResult published = ContentService.SaveAndPublish(content, "en-US"); Assert.IsFalse(published.Success); Assert.AreEqual(PublishResultType.FailedPublishCultureAwaitingRelease, published.Result); @@ -1472,8 +1500,8 @@ public void Cannot_Publish_Culture_Awaiting_Release() public void Cannot_Publish_Content_Where_Parent_Is_Unpublished() { // Arrange - IContent content = ContentService.Create("Subpage with Unpublished Parent", Textpage.Id, "umbTextpage", Constants.Security.SuperUserId); - ContentService.Save(content, Constants.Security.SuperUserId); + IContent content = ContentService.Create("Subpage with Unpublished Parent", Textpage.Id, "umbTextpage"); + ContentService.Save(content); // Act IEnumerable published = ContentService.SaveAndPublishBranch(content, true); @@ -1502,7 +1530,7 @@ public void Cannot_Publish_Trashed_Content() public void Can_Save_And_Publish_Content() { // Arrange - IContent content = ContentService.Create("Home US", -1, "umbTextpage", Constants.Security.SuperUserId); + IContent content = ContentService.Create("Home US", -1, "umbTextpage"); content.SetValue("author", "Barack Obama"); // Act @@ -1515,28 +1543,29 @@ public void Can_Save_And_Publish_Content() } /// - /// Try to immitate a new child content item being created through the UI. - /// This content item will have no Id, Path or Identity. - /// It seems like this is wiped somewhere in the process when creating an item through the UI - /// and we need to make sure we handle nullchecks for these properties when creating content. - /// This is unfortunately not caught by the normal ContentService tests. + /// Try to immitate a new child content item being created through the UI. + /// This content item will have no Id, Path or Identity. + /// It seems like this is wiped somewhere in the process when creating an item through the UI + /// and we need to make sure we handle nullchecks for these properties when creating content. + /// This is unfortunately not caught by the normal ContentService tests. /// [Test] public void Can_Save_And_Publish_Content_And_Child_Without_Identity() { // Arrange - IContent content = ContentService.Create("Home US", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); + IContent content = ContentService.Create("Home US", Constants.System.Root, "umbTextpage"); content.SetValue("author", "Barack Obama"); // Act PublishResult published = ContentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); - IContent childContent = ContentService.Create("Child", content.Id, "umbTextpage", Constants.Security.SuperUserId); + IContent childContent = ContentService.Create("Child", content.Id, "umbTextpage"); // Reset all identity properties childContent.Id = 0; childContent.Path = null; ((Content)childContent).ResetIdentity(); - PublishResult childPublished = ContentService.SaveAndPublish(childContent, userId: Constants.Security.SuperUserId); + PublishResult childPublished = + ContentService.SaveAndPublish(childContent, userId: Constants.Security.SuperUserId); // Assert Assert.That(content.HasIdentity, Is.True); @@ -1557,7 +1586,7 @@ public void Can_Get_Published_Descendant_Versions() IContent content = ContentService.GetById(Subpage.Id); content.Properties["title"].SetValue(content.Properties["title"].GetValue() + " Published"); PublishResult contentPublished = ContentService.SaveAndPublish(content); - int publishedVersion = content.VersionId; + var publishedVersion = content.VersionId; content.Properties["title"].SetValue(content.Properties["title"].GetValue() + " Saved"); ContentService.Save(content); @@ -1578,7 +1607,8 @@ public void Can_Get_Published_Descendant_Versions() // Ensure that the published content version has the correct property value and is marked as published IContent publishedContentVersion = publishedDescendants.First(x => x.VersionId == publishedVersion); Assert.That(publishedContentVersion.Published, Is.True); - Assert.That(publishedContentVersion.Properties["title"].GetValue(published: true), Contains.Substring("Published")); + Assert.That(publishedContentVersion.Properties["title"].GetValue(published: true), + Contains.Substring("Published")); // and has the correct draft properties Assert.That(publishedContentVersion.Properties["title"].GetValue(), Contains.Substring("Saved")); @@ -1595,11 +1625,11 @@ public void Can_Get_Published_Descendant_Versions() public void Can_Save_Content() { // Arrange - IContent content = ContentService.Create("Home US", -1, "umbTextpage", Constants.Security.SuperUserId); + IContent content = ContentService.Create("Home US", -1, "umbTextpage"); content.SetValue("author", "Barack Obama"); // Act - ContentService.Save(content, Constants.Security.SuperUserId); + ContentService.Save(content); // Assert Assert.That(content.HasIdentity, Is.True); @@ -1620,9 +1650,9 @@ public void Can_Update_Content_Property_Values() // re-get content = ContentService.GetById(content.Id); - content.SetValue("title", "another title of mine"); // Change a value - content.SetValue("bodyText", null); // Clear a value - content.SetValue("author", "new author"); // Add a value + content.SetValue("title", "another title of mine"); // Change a value + content.SetValue("bodyText", null); // Clear a value + content.SetValue("author", "new author"); // Add a value ContentService.SaveAndPublish(content); // re-get @@ -1634,17 +1664,17 @@ public void Can_Update_Content_Property_Values() content.SetValue("title", "new title"); content.SetValue("bodyText", "new body text"); content.SetValue("author", "new author text"); - ContentService.Save(content); // new non-published version + ContentService.Save(content); // new non-published version // re-get content = ContentService.GetById(content.Id); - content.SetValue("title", null); // Clear a value - content.SetValue("bodyText", null); // Clear a value - ContentService.Save(content); // saving non-published version + content.SetValue("title", null); // Clear a value + content.SetValue("bodyText", null); // Clear a value + ContentService.Save(content); // saving non-published version // re-get content = ContentService.GetById(content.Id); - Assert.IsNull(content.GetValue("title")); // Test clearing the value worked with the non-published version + Assert.IsNull(content.GetValue("title")); // Test clearing the value worked with the non-published version Assert.IsNull(content.GetValue("bodyText")); Assert.AreEqual("new author text", content.GetValue("author")); @@ -1665,7 +1695,7 @@ public void Can_Bulk_Save_Content() var list = new List { subpage, subpage2 }; // Act - ContentService.Save(list, Constants.Security.SuperUserId); + ContentService.Save(list); // Assert Assert.That(list.Any(x => !x.HasIdentity), Is.False); @@ -1678,7 +1708,7 @@ public void Can_Bulk_Save_New_Hierarchy_Content() var hierarchy = CreateContentHierarchy().ToList(); // Act - ContentService.Save(hierarchy, Constants.Security.SuperUserId); + ContentService.Save(hierarchy); Assert.That(hierarchy.Any(), Is.True); Assert.That(hierarchy.Any(x => x.HasIdentity == false), Is.False); @@ -1696,7 +1726,7 @@ public void Can_Delete_Content_Of_Specific_ContentType() // Act ContentService.DeleteOfType(contentType.Id); IEnumerable rootContent = ContentService.GetRootContent(); - IEnumerable contents = ContentService.GetPagedOfType(contentType.Id, 0, int.MaxValue, out long _, null); + IEnumerable contents = ContentService.GetPagedOfType(contentType.Id, 0, int.MaxValue, out var _); // Assert Assert.That(rootContent.Any(), Is.False); @@ -1710,7 +1740,7 @@ public void Can_Delete_Content() IContent content = ContentService.GetById(Textpage.Id); // Act - ContentService.Delete(content, Constants.Security.SuperUserId); + ContentService.Delete(content); IContent deleted = ContentService.GetById(Textpage.Id); // Assert @@ -1724,7 +1754,7 @@ public void Can_Move_Content_To_RecycleBin() IContent content = ContentService.GetById(Textpage.Id); // Act - ContentService.MoveToRecycleBin(content, Constants.Security.SuperUserId); + ContentService.MoveToRecycleBin(content); // Assert Assert.That(content.ParentId, Is.EqualTo(-20)); @@ -1737,12 +1767,12 @@ public void Can_Move_Content_Structure_To_RecycleBin_And_Empty_RecycleBin() IContentType contentType = ContentTypeService.Get("umbTextpage"); Content subsubpage = ContentBuilder.CreateSimpleContent(contentType, "Text Page 3", Subpage.Id); - ContentService.Save(subsubpage, Constants.Security.SuperUserId); + ContentService.Save(subsubpage); IContent content = ContentService.GetById(Textpage.Id); const int pageSize = 500; - int page = 0; - long total = long.MaxValue; + var page = 0; + var total = long.MaxValue; var descendants = new List(); while (page * pageSize < total) { @@ -1755,7 +1785,7 @@ public void Can_Move_Content_Structure_To_RecycleBin_And_Empty_RecycleBin() Assert.IsFalse(descendants.Any(x => x.Path.StartsWith("-1,-20,"))); Assert.IsFalse(descendants.Any(x => x.Trashed)); - ContentService.MoveToRecycleBin(content, Constants.Security.SuperUserId); + ContentService.MoveToRecycleBin(content); descendants.Clear(); page = 0; @@ -1770,8 +1800,8 @@ public void Can_Move_Content_Structure_To_RecycleBin_And_Empty_RecycleBin() Assert.IsTrue(descendants.All(x => x.Path.StartsWith("-1,-20,"))); Assert.True(descendants.All(x => x.Trashed)); - ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); - var trashed = ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out long _).ToList(); + ContentService.EmptyRecycleBin(); + var trashed = ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); Assert.IsEmpty(trashed); } @@ -1780,8 +1810,8 @@ public void Can_Empty_RecycleBin() { // Arrange // Act - ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); - var contents = ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out long _).ToList(); + ContentService.EmptyRecycleBin(); + var contents = ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); // Assert Assert.That(contents.Any(), Is.False); @@ -1797,10 +1827,11 @@ public void Ensures_Permissions_Are_Retained_For_Copied_Descendants_With_Explici Template template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id); + ContentType contentType = + ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id); contentType.AllowedContentTypes = new List { - new ContentTypeSort(new Lazy(() => contentType.Id), 0, contentType.Alias) + new(new Lazy(() => contentType.Id), 0, contentType.Alias) }; ContentTypeService.Save(contentType); @@ -1820,8 +1851,8 @@ public void Ensures_Permissions_Are_Retained_For_Copied_Descendants_With_Explici IContent copy = ContentService.Copy(childPage, parentPage2.Id, false, true); // get the permissions and verify - EntityPermissionSet permissions = UserService.GetPermissionsForPath(userGroup, copy.Path, fallbackToDefaultPermissions: true); - string[] allPermissions = permissions.GetAllPermissions().ToArray(); + EntityPermissionSet permissions = UserService.GetPermissionsForPath(userGroup, copy.Path, true); + var allPermissions = permissions.GetAllPermissions().ToArray(); Assert.AreEqual(1, allPermissions.Length); Assert.AreEqual("A", allPermissions[0]); } @@ -1836,10 +1867,11 @@ public void Ensures_Permissions_Are_Inherited_For_Copied_Descendants() Template template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id); + ContentType contentType = + ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id); contentType.AllowedContentTypes = new List { - new ContentTypeSort(new Lazy(() => contentType.Id), 0, contentType.Alias) + new(new Lazy(() => contentType.Id), 0, contentType.Alias) }; ContentTypeService.Save(contentType); @@ -1857,8 +1889,8 @@ public void Ensures_Permissions_Are_Inherited_For_Copied_Descendants() // Verify that the children have the inherited permissions var descendants = new List(); const int pageSize = 500; - int page = 0; - long total = long.MaxValue; + var page = 0; + var total = long.MaxValue; while (page * pageSize < total) { descendants.AddRange(ContentService.GetPagedDescendants(parentPage.Id, page++, pageSize, out total)); @@ -1868,8 +1900,8 @@ public void Ensures_Permissions_Are_Inherited_For_Copied_Descendants() foreach (IContent descendant in descendants) { - EntityPermissionSet permissions = UserService.GetPermissionsForPath(userGroup, descendant.Path, fallbackToDefaultPermissions: true); - string[] allPermissions = permissions.GetAllPermissions().ToArray(); + EntityPermissionSet permissions = UserService.GetPermissionsForPath(userGroup, descendant.Path, true); + var allPermissions = permissions.GetAllPermissions().ToArray(); Assert.AreEqual(1, allPermissions.Length); Assert.AreEqual("A", allPermissions[0]); } @@ -1893,8 +1925,8 @@ public void Ensures_Permissions_Are_Inherited_For_Copied_Descendants() foreach (IContent descendant in descendants) { - EntityPermissionSet permissions = UserService.GetPermissionsForPath(userGroup, descendant.Path, fallbackToDefaultPermissions: true); - string[] allPermissions = permissions.GetAllPermissions().ToArray(); + EntityPermissionSet permissions = UserService.GetPermissionsForPath(userGroup, descendant.Path, true); + var allPermissions = permissions.GetAllPermissions().ToArray(); Assert.AreEqual(1, allPermissions.Length); Assert.AreEqual("B", allPermissions[0]); } @@ -1914,22 +1946,19 @@ public void Can_Empty_RecycleBin_With_Content_That_Has_All_Related_Data() // * published & preview data // * multiple versions ContentType contentType = ContentTypeBuilder.CreateAllTypesContentType("test", "test"); - ContentTypeService.Save(contentType, Constants.Security.SuperUserId); + ContentTypeService.Save(contentType); object obj = - new - { - tags = "[\"Hello\",\"World\"]" - }; + new { tags = "[\"Hello\",\"World\"]" }; Content content1 = ContentBuilder.CreateBasicContent(contentType); content1.PropertyValues(obj); content1.ResetDirtyProperties(false); - ContentService.Save(content1, Constants.Security.SuperUserId); + ContentService.Save(content1); Assert.IsTrue(ContentService.SaveAndPublish(content1, userId: 0).Success); Content content2 = ContentBuilder.CreateBasicContent(contentType); content2.PropertyValues(obj); content2.ResetDirtyProperties(false); - ContentService.Save(content2, Constants.Security.SuperUserId); + ContentService.Save(content2); Assert.IsTrue(ContentService.SaveAndPublish(content2, userId: 0).Success); IUserGroup editorGroup = UserService.GetUserGroupByAlias(Constants.Security.EditorGroupAlias); @@ -1940,17 +1969,12 @@ public void Can_Empty_RecycleBin_With_Content_That_Has_All_Related_Data() admin.StartContentIds = new[] { content1.Id }; UserService.Save(admin); - RelationService.Save(new RelationType("test", "test", false, Constants.ObjectTypes.Document, Constants.ObjectTypes.Document)); + RelationService.Save(new RelationType("test", "test", false, Constants.ObjectTypes.Document, + Constants.ObjectTypes.Document)); Assert.IsNotNull(RelationService.Relate(content1, content2, "test")); - PublicAccessService.Save(new PublicAccessEntry(content1, content2, content2, new List - { - new PublicAccessRule - { - RuleType = "test", - RuleValue = "test" - } - })); + PublicAccessService.Save(new PublicAccessEntry(content1, content2, content2, + new List { new() { RuleType = "test", RuleValue = "test" } })); Assert.IsTrue(PublicAccessService.AddRule(content1, "test2", "test2").Success); IUser user = UserService.GetUserById(Constants.Security.SuperUserId); @@ -1959,15 +1983,13 @@ public void Can_Empty_RecycleBin_With_Content_That_Has_All_Related_Data() ContentService.SetPermission(content1, 'A', new[] { userGroup.Id }); - Assert.IsTrue(DomainService.Save(new UmbracoDomain("www.test.com", "en-AU") - { - RootContentId = content1.Id - }).Success); + Assert.IsTrue(DomainService.Save(new UmbracoDomain("www.test.com", "en-AU") { RootContentId = content1.Id }) + .Success); // Act - ContentService.MoveToRecycleBin(content1, Constants.Security.SuperUserId); - ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); - var contents = ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out long _).ToList(); + ContentService.MoveToRecycleBin(content1); + ContentService.EmptyRecycleBin(); + var contents = ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); // Assert Assert.That(contents.Any(), Is.False); @@ -1995,7 +2017,7 @@ public void Can_Copy_Content() IContent temp = ContentService.GetById(Subpage.Id); // Act - IContent copy = ContentService.Copy(temp, temp.ParentId, false, Constants.Security.SuperUserId); + IContent copy = ContentService.Copy(temp, temp.ParentId, false); IContent content = ContentService.GetById(Subpage.Id); // Assert @@ -2015,8 +2037,8 @@ public void Can_Copy_And_Modify_Content_With_Events() { // see https://github.com/umbraco/Umbraco-CMS/issues/5513 - bool copyingWasCalled = false; - bool copiedWasCalled = false; + var copyingWasCalled = false; + var copiedWasCalled = false; ContentNotificationHandler.CopyingContent = notification => { @@ -2028,8 +2050,8 @@ public void Can_Copy_And_Modify_Content_With_Events() ContentNotificationHandler.CopiedContent = notification => { - string copyVal = notification.Copy.GetValue("title"); - string origVal = notification.Original.GetValue("title"); + var copyVal = notification.Copy.GetValue("title"); + var origVal = notification.Original.GetValue("title"); Assert.AreEqual("1", copyVal); Assert.AreEqual("2", origVal); @@ -2048,7 +2070,7 @@ public void Can_Copy_And_Modify_Content_With_Events() content.SetValue("title", "New Value"); ContentService.Save(content); - IContent copy = ContentService.Copy(content, content.ParentId, false, Constants.Security.SuperUserId); + IContent copy = ContentService.Copy(content, content.ParentId, false); Assert.AreEqual("1", copy.GetValue("title")); Assert.IsTrue(copyingWasCalled); @@ -2070,7 +2092,7 @@ public void Can_Copy_Recursive() Assert.AreEqual(3, ContentService.CountChildren(temp.Id)); // Act - IContent copy = ContentService.Copy(temp, temp.ParentId, false, true, Constants.Security.SuperUserId); + IContent copy = ContentService.Copy(temp, temp.ParentId, false, true); IContent content = ContentService.GetById(Textpage.Id); // Assert @@ -2080,7 +2102,7 @@ public void Can_Copy_Recursive() Assert.AreEqual(3, ContentService.CountChildren(copy.Id)); IContent child = ContentService.GetById(Subpage.Id); - IContent childCopy = ContentService.GetPagedChildren(copy.Id, 0, 500, out long total).First(); + IContent childCopy = ContentService.GetPagedChildren(copy.Id, 0, 500, out var total).First(); Assert.AreEqual(childCopy.Name, child.Name); Assert.AreNotEqual(childCopy.Id, child.Id); Assert.AreNotEqual(childCopy.Key, child.Key); @@ -2095,7 +2117,7 @@ public void Can_Copy_NonRecursive() Assert.AreEqual(3, ContentService.CountChildren(temp.Id)); // Act - IContent copy = ContentService.Copy(temp, temp.ParentId, false, false, Constants.Security.SuperUserId); + IContent copy = ContentService.Copy(temp, temp.ParentId, false, false); IContent content = ContentService.GetById(Textpage.Id); // Assert @@ -2114,12 +2136,15 @@ public void Can_Copy_Content_With_Tags() // the property needs to support tags, else nothing works of course! Template template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - ContentType contentType = ContentTypeBuilder.CreateSimpleTagsContentType("umbTagsPage", "TagsPage", defaultTemplateId: template.Id); + ContentType contentType = + ContentTypeBuilder.CreateSimpleTagsContentType("umbTagsPage", "TagsPage", + defaultTemplateId: template.Id); contentType.Key = new Guid("78D96D30-1354-4A1E-8450-377764200C58"); ContentTypeService.Save(contentType); - Content content = ContentBuilder.CreateSimpleContent(contentType, "Simple Tags Page", Constants.System.Root); - content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, propAlias, new[] { "hello", "world" }); + Content content = ContentBuilder.CreateSimpleContent(contentType, "Simple Tags Page"); + content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, propAlias, + new[] { "hello", "world" }); ContentService.Save(content); // value has been set but no tags have been created (not published) @@ -2174,7 +2199,7 @@ public void Can_Rollback_Version_On_Content() var versions = ContentService.GetVersions(Subpage.Id).ToList(); Assert.AreEqual(1, versions.Count); - int version1 = content.VersionId; + var version1 = content.VersionId; content.Name = "Text Page 2 Updated"; content.SetValue("author", "Francis Doe"); @@ -2183,12 +2208,13 @@ public void Can_Rollback_Version_On_Content() Assert.IsTrue(content.Edited); ContentService.SaveAndPublish(content); // new version - int version2 = content.VersionId; + var version2 = content.VersionId; Assert.AreNotEqual(version1, version2); Assert.IsTrue(content.Published); Assert.IsFalse(content.Edited); - Assert.AreEqual("Francis Doe", ContentService.GetById(content.Id).GetValue("author")); // version2 author is Francis + Assert.AreEqual("Francis Doe", + ContentService.GetById(content.Id).GetValue("author")); // version2 author is Francis Assert.AreEqual("Text Page 2 Updated", content.Name); Assert.AreEqual("Text Page 2 Updated", content.PublishName); @@ -2207,12 +2233,13 @@ public void Can_Rollback_Version_On_Content() content.Name = "Text Page 2 ReReUpdated"; ContentService.SaveAndPublish(content); // new version - int version3 = content.VersionId; + var version3 = content.VersionId; Assert.AreNotEqual(version2, version3); Assert.IsTrue(content.Published); Assert.IsFalse(content.Edited); - Assert.AreEqual("Jane Doe", ContentService.GetById(content.Id).GetValue("author")); // version3 author is Jane + Assert.AreEqual("Jane Doe", + ContentService.GetById(content.Id).GetValue("author")); // version3 author is Jane Assert.AreEqual("Text Page 2 ReReUpdated", content.Name); Assert.AreEqual("Text Page 2 ReReUpdated", content.PublishName); @@ -2232,7 +2259,8 @@ public void Can_Rollback_Version_On_Content() Assert.IsNotNull(rollback); Assert.IsTrue(rollback.Published); Assert.IsTrue(rollback.Edited); - Assert.AreEqual("Francis Doe", ContentService.GetById(content.Id).GetValue("author")); // author is now Francis again + Assert.AreEqual("Francis Doe", + ContentService.GetById(content.Id).GetValue("author")); // author is now Francis again Assert.AreEqual(version3, rollback.VersionId); // same version but with edits // props and name have rolled back @@ -2291,7 +2319,8 @@ public void Can_Rollback_Version_On_Multilingual() Template template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("multi", "Multi", defaultTemplateId: template.Id); + ContentType contentType = + ContentTypeBuilder.CreateSimpleContentType("multi", "Multi", defaultTemplateId: template.Id); contentType.Key = new Guid("45FF9A70-9C5F-448D-A476-DCD23566BBF8"); contentType.Variations = ContentVariation.Culture; IPropertyType p1 = contentType.PropertyTypes.First(); @@ -2311,13 +2340,13 @@ public void Can_Rollback_Version_On_Multilingual() page.SetCultureName("da1", langDa.IsoCode); Thread.Sleep(1); ContentService.Save(page); - int versionId0 = page.VersionId; + var versionId0 = page.VersionId; page.SetValue(p1.Alias, "v1fr", langFr.IsoCode); page.SetValue(p1.Alias, "v1da", langDa.IsoCode); Thread.Sleep(1); ContentService.SaveAndPublish(page); - int versionId1 = page.VersionId; + var versionId1 = page.VersionId; Thread.Sleep(10); @@ -2325,7 +2354,7 @@ public void Can_Rollback_Version_On_Multilingual() page.SetValue(p1.Alias, "v2fr", langFr.IsoCode); Thread.Sleep(1); ContentService.SaveAndPublish(page, langFr.IsoCode); - int versionId2 = page.VersionId; + var versionId2 = page.VersionId; Thread.Sleep(10); @@ -2333,7 +2362,7 @@ public void Can_Rollback_Version_On_Multilingual() page.SetValue(p1.Alias, "v2da", langDa.IsoCode); Thread.Sleep(1); ContentService.SaveAndPublish(page, langDa.IsoCode); - int versionId3 = page.VersionId; + var versionId3 = page.VersionId; Thread.Sleep(10); @@ -2343,7 +2372,7 @@ public void Can_Rollback_Version_On_Multilingual() page.SetValue(p1.Alias, "v3da", langDa.IsoCode); Thread.Sleep(1); ContentService.SaveAndPublish(page); - int versionId4 = page.VersionId; + var versionId4 = page.VersionId; // now get all versions IContent[] versions = ContentService.GetVersions(page.Id).ToArray(); @@ -2395,14 +2424,14 @@ public void Can_Rollback_Version_On_Multilingual() Assert.AreEqual("da3", versions[0].GetCultureName(langDa.IsoCode)); // all versions have the same publish infos - for (int i = 0; i < 5; i++) + for (var i = 0; i < 5; i++) { Assert.AreEqual(versions[0].PublishDate, versions[i].PublishDate); Assert.AreEqual(versions[0].GetPublishDate(langFr.IsoCode), versions[i].GetPublishDate(langFr.IsoCode)); Assert.AreEqual(versions[0].GetPublishDate(langDa.IsoCode), versions[i].GetPublishDate(langDa.IsoCode)); } - for (int i = 0; i < 5; i++) + for (var i = 0; i < 5; i++) { Console.Write("[{0}] ", i); Console.WriteLine(versions[i].UpdateDate.ToString("O")[11..]); @@ -2444,7 +2473,7 @@ public void Can_Rollback_Version_On_Multilingual() // helps showcase the functionality is actually working Thread.Sleep(5); ContentService.Save(page); - int versionId5 = page.VersionId; + var versionId5 = page.VersionId; versions = ContentService.GetVersions(page.Id).ToArray(); @@ -2452,7 +2481,7 @@ public void Can_Rollback_Version_On_Multilingual() Assert.AreEqual(5, versions.Length); Assert.AreEqual(versionId4, versionId5); - for (int i = 0; i < 5; i++) + for (var i = 0; i < 5; i++) { Console.Write("[{0}] ", i); Console.WriteLine(versions[i].UpdateDate.ToString("O")[11..]); @@ -2465,7 +2494,7 @@ public void Can_Rollback_Version_On_Multilingual() IContent[] versionsSlim = ContentService.GetVersionsSlim(page.Id, 0, 50).ToArray(); Assert.AreEqual(5, versionsSlim.Length); - for (int i = 0; i < 5; i++) + for (var i = 0; i < 5; i++) { Console.Write("[{0}] ", i); Console.WriteLine(versionsSlim[i].UpdateDate.Ticks); @@ -2476,7 +2505,8 @@ public void Can_Rollback_Version_On_Multilingual() Console.WriteLine("-"); // what we do in the controller to get rollback versions - IContent[] versionsSlimFr = versionsSlim.Where(x => x.UpdateDate == x.GetUpdateDate(langFr.IsoCode)).ToArray(); + IContent[] versionsSlimFr = + versionsSlim.Where(x => x.UpdateDate == x.GetUpdateDate(langFr.IsoCode)).ToArray(); Assert.AreEqual(4, versionsSlimFr.Length); @@ -2506,8 +2536,10 @@ public void Can_Save_Lazy_Content() IContentType contentType = ContentTypeService.Get("umbTextpage"); IContent root = ContentService.GetById(Textpage.Id); - var c = new Lazy(() => ContentBuilder.CreateSimpleContent(contentType, "Hierarchy Simple Text Page", root.Id)); - var c2 = new Lazy(() => ContentBuilder.CreateSimpleContent(contentType, "Hierarchy Simple Text Subpage", c.Value.Id)); + var c = new Lazy(() => + ContentBuilder.CreateSimpleContent(contentType, "Hierarchy Simple Text Page", root.Id)); + var c2 = new Lazy(() => + ContentBuilder.CreateSimpleContent(contentType, "Hierarchy Simple Text Subpage", c.Value.Id)); var list = new List> { c, c2 }; using (IScope scope = ScopeProvider.CreateScope()) @@ -2537,9 +2569,10 @@ public void Can_Verify_Property_Types_On_Content() IContentTypeService contentTypeService = ContentTypeService; ContentType contentType = ContentTypeBuilder.CreateAllTypesContentType("allDataTypes", "All DataTypes"); ContentTypeService.Save(contentType); - Content content = ContentBuilder.CreateAllTypesContent(contentType, "Random Content", Constants.System.Root); + Content content = + ContentBuilder.CreateAllTypesContent(contentType, "Random Content", Constants.System.Root); ContentService.Save(content); - int id = content.Id; + var id = content.Id; // Act IContent sut = ContentService.GetById(id); @@ -2555,17 +2588,26 @@ public void Can_Verify_Property_Types_On_Content() // SD: This is failing because the 'content' call to GetValue always has empty milliseconds // MCH: I'm guessing this is an issue because of the format the date is actually stored as, right? Cause we don't do any formatting when saving or loading - Assert.That(sut.GetValue("dateTime").ToString("G"), Is.EqualTo(content.GetValue("dateTime").ToString("G"))); + Assert.That(sut.GetValue("dateTime").ToString("G"), + Is.EqualTo(content.GetValue("dateTime").ToString("G"))); Assert.That(sut.GetValue("colorPicker"), Is.EqualTo("black")); Assert.That(sut.GetValue("ddlMultiple"), Is.EqualTo("1234,1235")); Assert.That(sut.GetValue("rbList"), Is.EqualTo("random")); - Assert.That(sut.GetValue("date").ToString("G"), Is.EqualTo(content.GetValue("date").ToString("G"))); + Assert.That(sut.GetValue("date").ToString("G"), + Is.EqualTo(content.GetValue("date").ToString("G"))); Assert.That(sut.GetValue("ddl"), Is.EqualTo("1234")); Assert.That(sut.GetValue("chklist"), Is.EqualTo("randomc")); - Assert.That(sut.GetValue("contentPicker"), Is.EqualTo(Udi.Create(Constants.UdiEntityType.Document, new Guid("74ECA1D4-934E-436A-A7C7-36CC16D4095C")))); - Assert.That(sut.GetValue("mediaPicker"), Is.EqualTo(Udi.Create(Constants.UdiEntityType.Media, new Guid("44CB39C8-01E5-45EB-9CF8-E70AAF2D1691")))); - Assert.That(sut.GetValue("memberPicker"), Is.EqualTo(Udi.Create(Constants.UdiEntityType.Member, new Guid("9A50A448-59C0-4D42-8F93-4F1D55B0F47D")))); - Assert.That(sut.GetValue("multiUrlPicker"), Is.EqualTo("[{\"name\":\"https://test.com\",\"url\":\"https://test.com\"}]")); + Assert.That(sut.GetValue("contentPicker"), + Is.EqualTo(Udi.Create(Constants.UdiEntityType.Document, + new Guid("74ECA1D4-934E-436A-A7C7-36CC16D4095C")))); + Assert.That(sut.GetValue("mediaPicker"), + Is.EqualTo(Udi.Create(Constants.UdiEntityType.Media, + new Guid("44CB39C8-01E5-45EB-9CF8-E70AAF2D1691")))); + Assert.That(sut.GetValue("memberPicker"), + Is.EqualTo(Udi.Create(Constants.UdiEntityType.Member, + new Guid("9A50A448-59C0-4D42-8F93-4F1D55B0F47D")))); + Assert.That(sut.GetValue("multiUrlPicker"), + Is.EqualTo("[{\"name\":\"https://test.com\",\"url\":\"https://test.com\"}]")); Assert.That(sut.GetValue("tags"), Is.EqualTo("this,is,tags")); } @@ -2574,10 +2616,10 @@ public void Can_Delete_Previous_Versions_Not_Latest() { // Arrange IContent content = ContentService.GetById(Trashed.Id); - int version = content.VersionId; + var version = content.VersionId; // Act - ContentService.DeleteVersion(Trashed.Id, version, true, Constants.Security.SuperUserId); + ContentService.DeleteVersion(Trashed.Id, version, true); IContent sut = ContentService.GetById(Trashed.Id); // Assert @@ -2589,20 +2631,20 @@ public void Can_Get_Paged_Children() { // Start by cleaning the "db" IContent umbTextPage = ContentService.GetById(new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0")); - ContentService.Delete(umbTextPage, Constants.Security.SuperUserId); + ContentService.Delete(umbTextPage); Template template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); ContentType contentType = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: template.Id); ContentTypeService.Save(contentType); - for (int i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { Content c1 = ContentBuilder.CreateSimpleContent(contentType); ContentService.Save(c1); } - IContent[] entities = ContentService.GetPagedChildren(Constants.System.Root, 0, 6, out long total).ToArray(); + IContent[] entities = ContentService.GetPagedChildren(Constants.System.Root, 0, 6, out var total).ToArray(); Assert.That(entities.Length, Is.EqualTo(6)); Assert.That(total, Is.EqualTo(10)); entities = ContentService.GetPagedChildren(Constants.System.Root, 1, 6, out total).ToArray(); @@ -2615,7 +2657,7 @@ public void Can_Get_Paged_Children_Dont_Get_Descendants() { // Start by cleaning the "db" IContent umbTextPage = ContentService.GetById(new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0")); - ContentService.Delete(umbTextPage, Constants.Security.SuperUserId); + ContentService.Delete(umbTextPage); Template template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); @@ -2624,7 +2666,7 @@ public void Can_Get_Paged_Children_Dont_Get_Descendants() ContentTypeService.Save(contentType); // Only add 9 as we also add a content with children - for (int i = 0; i < 9; i++) + for (var i = 0; i < 9; i++) { Content c1 = ContentBuilder.CreateSimpleContent(contentType); ContentService.Save(c1); @@ -2632,14 +2674,14 @@ public void Can_Get_Paged_Children_Dont_Get_Descendants() Content willHaveChildren = ContentBuilder.CreateSimpleContent(contentType); ContentService.Save(willHaveChildren); - for (int i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { Content c1 = ContentBuilder.CreateSimpleContent(contentType, "Content" + i, willHaveChildren.Id); ContentService.Save(c1); } // children in root including the folder - not the descendants in the folder - IContent[] entities = ContentService.GetPagedChildren(Constants.System.Root, 0, 6, out long total).ToArray(); + IContent[] entities = ContentService.GetPagedChildren(Constants.System.Root, 0, 6, out var total).ToArray(); Assert.That(entities.Length, Is.EqualTo(6)); Assert.That(total, Is.EqualTo(10)); entities = ContentService.GetPagedChildren(Constants.System.Root, 1, 6, out total).ToArray(); @@ -2658,22 +2700,17 @@ public void Can_Get_Paged_Children_Dont_Get_Descendants() [Test] public void PublishingTest() { - var contentType = new ContentType(ShortStringHelper, Constants.System.Root) - { - Alias = "foo", - Name = "Foo" - }; + var contentType = new ContentType(ShortStringHelper, Constants.System.Root) { Alias = "foo", Name = "Foo" }; var properties = new PropertyTypeCollection(true) { - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext) { Alias = "title", Name = "Title", Mandatory = false, DataTypeId = -88 }, + new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext) + { + Alias = "title", Name = "Title", Mandatory = false, DataTypeId = -88 + } }; - contentType.PropertyGroups.Add(new PropertyGroup(properties) - { - Alias = "content", - Name = "content" - }); + contentType.PropertyGroups.Add(new PropertyGroup(properties) { Alias = "content", Name = "content" }); contentType.SetDefaultTemplate(new Template(ShortStringHelper, "Textpage", "textpage")); FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! @@ -2733,8 +2770,8 @@ public void PublishingTest() Assert.AreEqual("foo", content.GetValue("title", published: true)); Assert.AreEqual("foo", content.GetValue("title")); - int vpk = ((Content)content).VersionId; - int ppk = ((Content)content).PublishedVersionId; + var vpk = ((Content)content).VersionId; + var ppk = ((Content)content).PublishedVersionId; content = ContentService.GetById(content.Id); Assert.IsFalse(content.Published); @@ -2808,7 +2845,8 @@ public void Ensure_Invariant_Name() IContentType contentType = ContentTypeService.Get("umbTextpage"); contentType.Variations = ContentVariation.Culture; - contentType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Nvarchar, "prop") { Variations = ContentVariation.Culture }); + contentType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, + ValueStorageType.Nvarchar, "prop") { Variations = ContentVariation.Culture }); ContentTypeService.Save(contentType); var content = new Content(null, Constants.System.Root, contentType); @@ -2853,17 +2891,19 @@ public void Ensure_Unique_Culture_Names() content.SetCultureName("root", langUk.IsoCode); ContentService.Save(content); - for (int i = 0; i < 5; i++) + for (var i = 0; i < 5; i++) { var child = new Content(null, content, contentType); child.SetCultureName("child", langUk.IsoCode); ContentService.Save(child); - Assert.AreEqual("child" + (i == 0 ? string.Empty : " (" + i + ")"), child.GetCultureName(langUk.IsoCode)); + Assert.AreEqual("child" + (i == 0 ? string.Empty : " (" + i + ")"), + child.GetCultureName(langUk.IsoCode)); // Save it again to ensure that the unique check is not performed again against it's own name ContentService.Save(child); - Assert.AreEqual("child" + (i == 0 ? string.Empty : " (" + i + ")"), child.GetCultureName(langUk.IsoCode)); + Assert.AreEqual("child" + (i == 0 ? string.Empty : " (" + i + ")"), + child.GetCultureName(langUk.IsoCode)); } } @@ -2894,8 +2934,8 @@ public void Can_Get_Paged_Children_WithFilterAndOrder() contentType.Variations = ContentVariation.Culture; ContentTypeService.Save(contentType); - int[] o = new[] { 2, 1, 3, 0, 4 }; // randomly different - for (int i = 0; i < 5; i++) + int[] o = { 2, 1, 3, 0, 4 }; // randomly different + for (var i = 0; i < 5; i++) { var contentA = new Content(null, Constants.System.Root, contentType); contentA.SetCultureName("contentA" + i + "uk", langUk.IsoCode); @@ -2911,7 +2951,7 @@ public void Can_Get_Paged_Children_WithFilterAndOrder() } // get all - var list = ContentService.GetPagedChildren(Constants.System.Root, 0, 100, out long total).ToList(); + var list = ContentService.GetPagedChildren(Constants.System.Root, 0, 100, out var total).ToList(); Console.WriteLine("ALL"); WriteList(list); @@ -2964,7 +3004,7 @@ public void Can_Get_Paged_Children_WithFilterAndOrder() Assert.AreEqual(5, total); Assert.AreEqual(5, list.Count); - for (int i = 0; i < 5; i++) + for (var i = 0; i < 5; i++) { Assert.AreEqual("contentA" + i + "fr", list[i].GetCultureName(langFr.IsoCode)); } @@ -2975,7 +3015,7 @@ public void Can_Get_Paged_Children_WithFilterAndOrder() 100, out total, sqlContext.Query().Where(x => x.Name.Contains("contentA")), - Ordering.By("name", direction: Direction.Descending, culture: langFr.IsoCode)).ToList(); + Ordering.By("name", Direction.Descending, langFr.IsoCode)).ToList(); Console.WriteLine("FILTER BY NAME fr:'contentA', ORDER DESC"); WriteList(list); @@ -2983,7 +3023,7 @@ public void Can_Get_Paged_Children_WithFilterAndOrder() Assert.AreEqual(5, total); Assert.AreEqual(5, list.Count); - for (int i = 0; i < 5; i++) + for (var i = 0; i < 5; i++) { Assert.AreEqual("contentA" + (4 - i) + "fr", list[i].GetCultureName(langFr.IsoCode)); } @@ -2993,7 +3033,8 @@ private void WriteList(List list) { foreach (IContent content in list) { - Console.WriteLine("[{0}] {1} {2} {3} {4}", content.Id, content.Name, content.GetCultureName("en-GB"), content.GetCultureName("fr-FR"), content.GetCultureName("da-DK")); + Console.WriteLine("[{0}] {1} {2} {3} {4}", content.Id, content.Name, content.GetCultureName("en-GB"), + content.GetCultureName("fr-FR"), content.GetCultureName("da-DK")); } Console.WriteLine("-"); @@ -3008,14 +3049,14 @@ public void Can_SaveRead_Variations() .WithIsDefault(true) .Build(); ILanguage langFr = new LanguageBuilder() - .WithCultureInfo("fr-FR") - .Build(); + .WithCultureInfo("fr-FR") + .Build(); ILanguage langUk = new LanguageBuilder() - .WithCultureInfo("en-GB") - .Build(); + .WithCultureInfo("en-GB") + .Build(); ILanguage langDe = new LanguageBuilder() - .WithCultureInfo("de-DE") - .Build(); + .WithCultureInfo("de-DE") + .Build(); languageService.Save(langFr); languageService.Save(langUk); @@ -3025,7 +3066,8 @@ public void Can_SaveRead_Variations() IContentType contentType = ContentTypeService.Get("umbTextpage"); contentType.Variations = ContentVariation.Culture; - contentType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Nvarchar, "prop") { Variations = ContentVariation.Culture }); + contentType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, + ValueStorageType.Nvarchar, "prop") { Variations = ContentVariation.Culture }); // FIXME: add test w/ an invariant prop ContentTypeService.Save(contentType); @@ -3065,12 +3107,16 @@ public void Can_SaveRead_Variations() Assert.IsNull(content2.GetPublishName(langUk.IsoCode)); // only fr and uk have a name, and are available - AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), + (langDe, false)); // nothing has been published yet - AssertPerCulture(content, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, false), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, false), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, false), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, false), + (langDe, false)); // not published => must be edited, if available AssertPerCulture(content, (x, c) => x.IsCultureEdited(c), (langFr, true), (langUk, true), (langDe, false)); @@ -3102,19 +3148,27 @@ public void Can_SaveRead_Variations() Assert.AreEqual("value-uk1", content2.GetValue("prop", langUk.IsoCode, published: true)); // no change - AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), + (langDe, false)); // fr and uk have been published now - AssertPerCulture(content, (x, c) => x.IsCulturePublished(c), (langFr, true), (langUk, true), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCulturePublished(c), (langFr, true), (langUk, true), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCulturePublished(c), (langFr, true), (langUk, true), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCulturePublished(c), (langFr, true), (langUk, true), + (langDe, false)); // fr and uk, published without changes, not edited - AssertPerCulture(content, (x, c) => x.IsCultureEdited(c), (langFr, false), (langUk, false), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCultureEdited(c), (langFr, false), (langUk, false), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCultureEdited(c), (langFr, false), (langUk, false), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCultureEdited(c), (langFr, false), (langUk, false), + (langDe, false)); - AssertPerCulture(content, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langFr, false), (langUk, false)); // DE would throw - AssertPerCulture(content2, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langFr, false), (langUk, false)); // DE would throw + AssertPerCulture(content, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langFr, false), + (langUk, false)); // DE would throw + AssertPerCulture(content2, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langFr, false), + (langUk, false)); // DE would throw // note that content and content2 culture published dates might be slightly different due to roundtrip to database @@ -3155,19 +3209,25 @@ public void Can_SaveRead_Variations() Assert.AreEqual("value-uk1", content2.GetValue("prop", langUk.IsoCode, published: true)); // no change - AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), + (langDe, false)); // no change - AssertPerCulture(content, (x, c) => x.IsCulturePublished(c), (langFr, true), (langUk, true), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCulturePublished(c), (langFr, true), (langUk, true), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCulturePublished(c), (langFr, true), (langUk, true), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCulturePublished(c), (langFr, true), (langUk, true), + (langDe, false)); // we have changed values so now fr and uk are edited AssertPerCulture(content, (x, c) => x.IsCultureEdited(c), (langFr, true), (langUk, true), (langDe, false)); AssertPerCulture(content2, (x, c) => x.IsCultureEdited(c), (langFr, true), (langUk, true), (langDe, false)); - AssertPerCulture(content, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langFr, false), (langUk, false)); // DE would throw - AssertPerCulture(content2, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langFr, false), (langUk, false)); // DE would throw + AssertPerCulture(content, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langFr, false), + (langUk, false)); // DE would throw + AssertPerCulture(content2, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langFr, false), + (langUk, false)); // DE would throw // Act // cannot just 'save' since we are changing what's published! @@ -3195,19 +3255,25 @@ public void Can_SaveRead_Variations() Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); // no change - AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), + (langDe, false)); // fr is not published anymore - AssertPerCulture(content, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), + (langDe, false)); // and so, fr has to be edited AssertPerCulture(content, (x, c) => x.IsCultureEdited(c), (langFr, true), (langUk, true), (langDe, false)); AssertPerCulture(content2, (x, c) => x.IsCultureEdited(c), (langFr, true), (langUk, true), (langDe, false)); - AssertPerCulture(content, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langUk, false)); // FR, DE would throw - AssertPerCulture(content2, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langUk, false)); // FR, DE would throw + AssertPerCulture(content, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, + (langUk, false)); // FR, DE would throw + AssertPerCulture(content2, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, + (langUk, false)); // FR, DE would throw // Act ContentService.Unpublish(content); @@ -3236,22 +3302,29 @@ public void Can_SaveRead_Variations() Assert.AreEqual("value-fr2", content2.GetValue("prop", langFr.IsoCode)); Assert.AreEqual("value-uk2", content2.GetValue("prop", langUk.IsoCode)); Assert.IsNull(content2.GetValue("prop", langFr.IsoCode, published: true)); - Assert.AreEqual("value-uk1", content2.GetValue("prop", langUk.IsoCode, published: true)); // has value, see note above + Assert.AreEqual("value-uk1", + content2.GetValue("prop", langUk.IsoCode, published: true)); // has value, see note above // no change - AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), + (langDe, false)); // fr is not published anymore - uk still is, see note above - AssertPerCulture(content, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), + (langDe, false)); // and so, fr has to be edited - uk still is AssertPerCulture(content, (x, c) => x.IsCultureEdited(c), (langFr, true), (langUk, true), (langDe, false)); AssertPerCulture(content2, (x, c) => x.IsCultureEdited(c), (langFr, true), (langUk, true), (langDe, false)); - AssertPerCulture(content, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langUk, false)); // FR, DE would throw - AssertPerCulture(content2, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langUk, false)); // FR, DE would throw + AssertPerCulture(content, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, + (langUk, false)); // FR, DE would throw + AssertPerCulture(content2, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, + (langUk, false)); // FR, DE would throw // Act @@ -3281,19 +3354,25 @@ public void Can_SaveRead_Variations() Assert.AreEqual("value-uk1", content2.GetValue("prop", langUk.IsoCode, published: true)); // no change - AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), + (langDe, false)); // no change, back to published - AssertPerCulture(content, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), + (langDe, false)); // no change, back to published AssertPerCulture(content, (x, c) => x.IsCultureEdited(c), (langFr, true), (langUk, true), (langDe, false)); AssertPerCulture(content2, (x, c) => x.IsCultureEdited(c), (langFr, true), (langUk, true), (langDe, false)); - AssertPerCulture(content, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langUk, false)); // FR, DE would throw - AssertPerCulture(content2, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langUk, false)); // FR, DE would throw + AssertPerCulture(content, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, + (langUk, false)); // FR, DE would throw + AssertPerCulture(content2, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, + (langUk, false)); // FR, DE would throw // Act ContentService.SaveAndPublish(content, langUk.IsoCode); @@ -3301,19 +3380,26 @@ public void Can_SaveRead_Variations() content2 = ContentService.GetById(content.Id); // no change - AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), + (langDe, false)); // no change - AssertPerCulture(content, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), (langDe, false)); + AssertPerCulture(content, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), + (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCulturePublished(c), (langFr, false), (langUk, true), + (langDe, false)); // now, uk is no more edited AssertPerCulture(content, (x, c) => x.IsCultureEdited(c), (langFr, true), (langUk, false), (langDe, false)); - AssertPerCulture(content2, (x, c) => x.IsCultureEdited(c), (langFr, true), (langUk, false), (langDe, false)); + AssertPerCulture(content2, (x, c) => x.IsCultureEdited(c), (langFr, true), (langUk, false), + (langDe, false)); - AssertPerCulture(content, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langUk, false)); // FR, DE would throw - AssertPerCulture(content2, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, (langUk, false)); // FR, DE would throw + AssertPerCulture(content, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, + (langUk, false)); // FR, DE would throw + AssertPerCulture(content2, (x, c) => x.GetPublishDate(c) == DateTime.MinValue, + (langUk, false)); // FR, DE would throw // Act content.SetCultureName("name-uk3", langUk.IsoCode); @@ -3329,12 +3415,14 @@ public void Can_SaveRead_Variations() Assert.IsTrue(content2.IsCultureEdited(langUk.IsoCode)); } - private void AssertPerCulture(IContent item, Func getter, params (ILanguage Language, bool Result)[] testCases) + private void AssertPerCulture(IContent item, Func getter, + params (ILanguage Language, bool Result)[] testCases) { foreach ((ILanguage Language, bool Result) testCase in testCases) { T value = getter(item, testCase.Language.IsoCode); - Assert.AreEqual(testCase.Result, value, $"Expected {testCase.Result} and got {value} for culture {testCase.Language.IsoCode}."); + Assert.AreEqual(testCase.Result, value, + $"Expected {testCase.Result} and got {value} for culture {testCase.Language.IsoCode}."); } } @@ -3345,9 +3433,10 @@ private IEnumerable CreateContentHierarchy() var list = new List(); - for (int i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { - Content content = ContentBuilder.CreateSimpleContent(contentType, "Hierarchy Simple Text Page " + i, root); + Content content = + ContentBuilder.CreateSimpleContent(contentType, "Hierarchy Simple Text Page " + i, root); list.Add(content); list.AddRange(CreateChildrenOf(contentType, content, 4)); @@ -3361,9 +3450,10 @@ private IEnumerable CreateContentHierarchy() private IEnumerable CreateChildrenOf(IContentType contentType, IContent content, int depth) { var list = new List(); - for (int i = 0; i < depth; i++) + for (var i = 0; i < depth; i++) { - Content c = ContentBuilder.CreateSimpleContent(contentType, "Hierarchy Simple Text Subpage " + i, content); + Content c = ContentBuilder.CreateSimpleContent(contentType, "Hierarchy Simple Text Subpage " + i, + content); list.Add(c); Debug.Print("Created: 'Hierarchy Simple Text Subpage {0}' - Depth: {1}", i, depth); @@ -3372,7 +3462,8 @@ private IEnumerable CreateChildrenOf(IContentType contentType, IConten return list; } - private void CreateEnglishAndFrenchDocumentType(out Language langUk, out Language langFr, out ContentType contentType) + private void CreateEnglishAndFrenchDocumentType(out Language langUk, out Language langFr, + out ContentType contentType) { langUk = (Language)new LanguageBuilder() .WithCultureInfo("en-GB") @@ -3389,7 +3480,8 @@ private void CreateEnglishAndFrenchDocumentType(out Language langUk, out Languag ContentTypeService.Save(contentType); } - private IContent CreateEnglishAndFrenchDocument(out Language langUk, out Language langFr, out ContentType contentType) + private IContent CreateEnglishAndFrenchDocument(out Language langUk, out Language langFr, + out ContentType contentType) { CreateEnglishAndFrenchDocumentType(out langUk, out langFr, out contentType); @@ -3405,17 +3497,16 @@ public class ContentNotificationHandler : INotificationHandler, INotificationHandler { - public void Handle(ContentPublishingNotification notification) => PublishingContent?.Invoke(notification); - - public void Handle(ContentCopyingNotification notification) => CopyingContent?.Invoke(notification); - - public void Handle(ContentCopiedNotification notification) => CopiedContent?.Invoke(notification); - public static Action PublishingContent { get; set; } public static Action CopyingContent { get; set; } public static Action CopiedContent { get; set; } + + public void Handle(ContentCopiedNotification notification) => CopiedContent?.Invoke(notification); + + public void Handle(ContentCopyingNotification notification) => CopyingContent?.Invoke(notification); + public void Handle(ContentPublishingNotification notification) => PublishingContent?.Invoke(notification); } } } diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs index 8113c1b3e9e2..946d4a236a8d 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs @@ -52,9 +52,14 @@ protected override void BeforeHostStart(IHost host) protected override void CustomTestSetup(IUmbracoBuilder builder) { - InMemoryConfiguration[Constants.Configuration.ConfigNuCache + ":" + nameof(NuCacheSettings.NuCacheSerializerType)] = NuCacheSerializerType.JSON.ToString(); builder.AddNuCache(); builder.Services.AddUnique(); + builder.Services.PostConfigure(options => + { + options.NuCacheSerializerType = NuCacheSerializerType.JSON; + }); + + } private void AssertJsonStartsWith(int id, string expected) diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs index 31a4ee2c0dc7..514b600e4815 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs @@ -6,7 +6,13 @@ using System.Diagnostics; using System.Linq; using System.Xml.Linq; +using Microsoft.Extensions.Logging.Abstractions; +using Moq; using NUnit.Framework; +using Umbraco.Extensions; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Tests.Common.Builders; @@ -14,6 +20,12 @@ using Umbraco.Cms.Tests.Common.Testing; using Umbraco.Cms.Tests.Integration.Testing; using Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importing; +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.PropertyEditors; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.Media; +using Umbraco.Cms.Core.Strings; namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services { @@ -22,6 +34,14 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services public class EntityXmlSerializerTests : UmbracoIntegrationTest { private IEntityXmlSerializer Serializer => GetRequiredService(); + private IContentService ContentService => GetRequiredService(); + private IMediaService MediaService => GetRequiredService(); + private IUserService UserService => GetRequiredService(); + private IMediaTypeService MediaTypeService => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private IDataValueEditorFactory DataValueEditorFactory => GetRequiredService(); + private ILocalizedTextService TextService => GetRequiredService(); + private IFileService FileService => GetRequiredService(); [Test] public void Can_Export_Macro() @@ -89,6 +109,123 @@ public void Can_Export_Languages() Assert.That(xml.ToString(), Is.EqualTo(languageItemsElement.ToString())); } + [Test] + public void Can_Generate_Xml_Representation_Of_Content() + { + // Arrange + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); // else, FK violation on contentType! + var contentType = ContentTypeBuilder.CreateTextPageContentType( + defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); + + var content = ContentBuilder.CreateTextpageContent(contentType, "Root Home", -1); + ContentService.Save(content, Constants.Security.SuperUserId); + + var nodeName = content.ContentType.Alias.ToSafeAlias(ShortStringHelper); + var urlName = content.GetUrlSegment(ShortStringHelper, new[] { new DefaultUrlSegmentProvider(ShortStringHelper) }); + + // Act + XElement element = content.ToXml(Serializer); + + // Assert + Assert.That(element, Is.Not.Null); + Assert.That(element.Name.LocalName, Is.EqualTo(nodeName)); + Assert.AreEqual(content.Id.ToString(), (string)element.Attribute("id")); + Assert.AreEqual(content.ParentId.ToString(), (string)element.Attribute("parentID")); + Assert.AreEqual(content.Level.ToString(), (string)element.Attribute("level")); + Assert.AreEqual(content.CreatorId.ToString(), (string)element.Attribute("creatorID")); + Assert.AreEqual(content.SortOrder.ToString(), (string)element.Attribute("sortOrder")); + Assert.AreEqual(content.CreateDate.ToString("s"), (string)element.Attribute("createDate")); + Assert.AreEqual(content.UpdateDate.ToString("s"), (string)element.Attribute("updateDate")); + Assert.AreEqual(content.Name, (string)element.Attribute("nodeName")); + Assert.AreEqual(urlName, (string)element.Attribute("urlName")); + Assert.AreEqual(content.Path, (string)element.Attribute("path")); + Assert.AreEqual("", (string)element.Attribute("isDoc")); + Assert.AreEqual(content.ContentType.Id.ToString(), (string)element.Attribute("nodeType")); + Assert.AreEqual(content.GetCreatorProfile(UserService).Name, (string)element.Attribute("creatorName")); + Assert.AreEqual(content.GetWriterProfile(UserService).Name, (string)element.Attribute("writerName")); + Assert.AreEqual(content.WriterId.ToString(), (string)element.Attribute("writerID")); + Assert.AreEqual(content.TemplateId.ToString(), (string)element.Attribute("template")); + + Assert.AreEqual(content.Properties["title"].GetValue().ToString(), element.Elements("title").Single().Value); + Assert.AreEqual(content.Properties["bodyText"].GetValue().ToString(), element.Elements("bodyText").Single().Value); + Assert.AreEqual(content.Properties["keywords"].GetValue().ToString(), element.Elements("keywords").Single().Value); + Assert.AreEqual(content.Properties["description"].GetValue().ToString(), element.Elements("description").Single().Value); + } + + [Test] + public void Can_Generate_Xml_Representation_Of_Media() + { + // Arrange + var mediaType = MediaTypeBuilder.CreateImageMediaType("image2"); + + MediaTypeService.Save(mediaType); + + // reference, so static ctor runs, so event handlers register + // and then, this will reset the width, height... because the file does not exist, of course ;-( + var loggerFactory = NullLoggerFactory.Instance; + var scheme = Mock.Of(); + var contentSettings = new ContentSettings(); + + var mediaFileManager = new MediaFileManager( + Mock.Of(), + scheme, + loggerFactory.CreateLogger(), + ShortStringHelper, + Services, + Options.Create(new ContentSettings())); + + var ignored = new FileUploadPropertyEditor( + DataValueEditorFactory, + mediaFileManager, + Options.Create(contentSettings), + TextService, + Services.GetRequiredService(), + ContentService, + IOHelper); + + var media = MediaBuilder.CreateMediaImage(mediaType, -1); + media.WriterId = -1; // else it's zero and that's not a user and it breaks the tests + MediaService.Save(media, Constants.Security.SuperUserId); + + // so we have to force-reset these values because the property editor has cleared them + media.SetValue(Constants.Conventions.Media.Width, "200"); + media.SetValue(Constants.Conventions.Media.Height, "200"); + media.SetValue(Constants.Conventions.Media.Bytes, "100"); + media.SetValue(Constants.Conventions.Media.Extension, "png"); + + var nodeName = media.ContentType.Alias.ToSafeAlias(ShortStringHelper); + var urlName = media.GetUrlSegment(ShortStringHelper, new[] { new DefaultUrlSegmentProvider(ShortStringHelper) }); + + // Act + XElement element = media.ToXml(Serializer); + + // Assert + Assert.That(element, Is.Not.Null); + Assert.That(element.Name.LocalName, Is.EqualTo(nodeName)); + Assert.AreEqual(media.Id.ToString(), (string)element.Attribute("id")); + Assert.AreEqual(media.ParentId.ToString(), (string)element.Attribute("parentID")); + Assert.AreEqual(media.Level.ToString(), (string)element.Attribute("level")); + Assert.AreEqual(media.SortOrder.ToString(), (string)element.Attribute("sortOrder")); + Assert.AreEqual(media.CreateDate.ToString("s"), (string)element.Attribute("createDate")); + Assert.AreEqual(media.UpdateDate.ToString("s"), (string)element.Attribute("updateDate")); + Assert.AreEqual(media.Name, (string)element.Attribute("nodeName")); + Assert.AreEqual(urlName, (string)element.Attribute("urlName")); + Assert.AreEqual(media.Path, (string)element.Attribute("path")); + Assert.AreEqual("", (string)element.Attribute("isDoc")); + Assert.AreEqual(media.ContentType.Id.ToString(), (string)element.Attribute("nodeType")); + Assert.AreEqual(media.GetCreatorProfile(UserService).Name, (string)element.Attribute("writerName")); + Assert.AreEqual(media.CreatorId.ToString(), (string)element.Attribute("writerID")); + Assert.IsNull(element.Attribute("template")); + + Assert.AreEqual(media.Properties[Constants.Conventions.Media.File].GetValue().ToString(), element.Elements(Constants.Conventions.Media.File).Single().Value); + Assert.AreEqual(media.Properties[Constants.Conventions.Media.Width].GetValue().ToString(), element.Elements(Constants.Conventions.Media.Width).Single().Value); + Assert.AreEqual(media.Properties[Constants.Conventions.Media.Height].GetValue().ToString(), element.Elements(Constants.Conventions.Media.Height).Single().Value); + Assert.AreEqual(media.Properties[Constants.Conventions.Media.Bytes].GetValue().ToString(), element.Elements(Constants.Conventions.Media.Bytes).Single().Value); + Assert.AreEqual(media.Properties[Constants.Conventions.Media.Extension].GetValue().ToString(), element.Elements(Constants.Conventions.Media.Extension).Single().Value); + } + private void CreateDictionaryData() { ILocalizationService localizationService = GetRequiredService(); @@ -104,7 +241,7 @@ private void CreateDictionaryData() .Build(); localizationService.Save(languageEnGb); - var parentItem = new DictionaryItem("Parent") {Key = Guid.Parse("28f2e02a-8c66-4fcd-85e3-8524d551c0d3")}; + var parentItem = new DictionaryItem("Parent") { Key = Guid.Parse("28f2e02a-8c66-4fcd-85e3-8524d551c0d3") }; var parentTranslations = new List { new DictionaryTranslation(languageNbNo, "ForelderVerdi"), @@ -113,7 +250,7 @@ private void CreateDictionaryData() parentItem.Translations = parentTranslations; localizationService.Save(parentItem); - var childItem = new DictionaryItem(parentItem.Key, "Child"){Key = Guid.Parse("e7dba0a9-d517-4ba4-8e18-2764d392c611")}; + var childItem = new DictionaryItem(parentItem.Key, "Child") { Key = Guid.Parse("e7dba0a9-d517-4ba4-8e18-2764d392c611") }; var childTranslations = new List { new DictionaryTranslation(languageNbNo, "BarnVerdi"), diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/NuCacheRebuildTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/NuCacheRebuildTests.cs new file mode 100644 index 000000000000..ef7825ca4930 --- /dev/null +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/NuCacheRebuildTests.cs @@ -0,0 +1,87 @@ +using NUnit.Framework; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.PublishedCache; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +using Umbraco.Cms.Tests.Common.Builders; +using Umbraco.Cms.Tests.Common.Testing; +using Umbraco.Cms.Tests.Integration.Testing; + +namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services +{ + [TestFixture] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true)] + public class NuCacheRebuildTests : UmbracoIntegrationTest + { + private IFileService FileService => GetRequiredService(); + + private IContentService ContentService => GetRequiredService(); + + private IContentTypeService ContentTypeService => GetRequiredService(); + + private IPublishedSnapshotService PublishedSnapshotService => GetRequiredService(); + + [Test] + public void UnpublishedNameChanges() + { + var urlSegmentProvider = new DefaultUrlSegmentProvider(ShortStringHelper); + + Template template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + ContentType contentType = ContentTypeBuilder.CreateTextPageContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); + + Content content = ContentBuilder.CreateTextpageContent(contentType, "hello", Constants.System.Root); + + ContentService.SaveAndPublish(content); + IContent cachedContent = ContentService.GetById(content.Id); + var segment = urlSegmentProvider.GetUrlSegment(cachedContent); + + // Does a new node work? + + Assert.AreEqual("hello", segment); + + content.Name = "goodbye"; + cachedContent = ContentService.GetById(content.Id); + segment = urlSegmentProvider.GetUrlSegment(cachedContent); + + // We didn't save anything, so all should still be the same + + Assert.AreEqual("hello", segment); + + ContentService.Save(content); + cachedContent = ContentService.GetById(content.Id); + segment = urlSegmentProvider.GetUrlSegment(cachedContent); + + // At this point we have saved the new name, but not published. The url should still be the previous name + + Assert.AreEqual("hello", segment); + + PublishedSnapshotService.Rebuild(); + + cachedContent = ContentService.GetById(content.Id); + segment = urlSegmentProvider.GetUrlSegment(cachedContent); + + // After a rebuild, the unpublished name should still not be the url. + // This was previously incorrect, per #11074 + + Assert.AreEqual("hello", segment); + + ContentService.SaveAndPublish(content); + cachedContent = ContentService.GetById(content.Id); + segment = urlSegmentProvider.GetUrlSegment(cachedContent); + + // The page has now been published, so we should see the new url segment + Assert.AreEqual("goodbye", segment); + + PublishedSnapshotService.Rebuild(); + cachedContent = ContentService.GetById(content.Id); + segment = urlSegmentProvider.GetUrlSegment(cachedContent); + + // Just double checking that things remain after a rebuild + Assert.AreEqual("goodbye", segment); + } + } +} diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj index f1fa4a6a8b55..36c901773ee9 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj +++ b/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj @@ -1,4 +1,4 @@ - + net5.0 @@ -52,6 +52,8 @@ True ImportResources.resx + + @@ -99,7 +101,6 @@ - diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UrlAndDomains/DomainAndUrlsTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UrlAndDomains/DomainAndUrlsTests.cs new file mode 100644 index 000000000000..39a5fd2e5f0e --- /dev/null +++ b/tests/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UrlAndDomains/DomainAndUrlsTests.cs @@ -0,0 +1,153 @@ +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.Packaging; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Tests.Common; +using Umbraco.Cms.Tests.Common.Testing; +using Umbraco.Cms.Tests.Integration.Testing; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Tests.Integration.Umbraco.Web.BackOffice.UrlAndDomains +{ + [TestFixture] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Mapper = true, WithApplication = true, + Logger = UmbracoTestOptions.Logger.Console)] + public class DomainAndUrlsTests : UmbracoIntegrationTest + { + [SetUp] + public void Setup() + { + XDocument xml = PackageMigrationResource.GetEmbeddedPackageDataManifest(GetType()); + IPackagingService packagingService = GetRequiredService(); + InstallationSummary = packagingService.InstallCompiledPackageData(xml); + + Root = InstallationSummary.ContentInstalled.First(); + ContentService.SaveAndPublish(Root); + + var cultures = new List(); + cultures.Add(GetRequiredService().GetDefaultLanguageIsoCode()); + + foreach (ILanguage language in InstallationSummary.LanguagesInstalled) + { + cultures.Add(language.IsoCode); + } + + Cultures = cultures.ToArray(); + + IHttpContextAccessor httpContextAccessor = GetRequiredService(); + + httpContextAccessor.HttpContext = new DefaultHttpContext + { + Request = + { + Scheme = "https", + Host = new HostString("localhost"), + Path = "/", + QueryString = new QueryString(string.Empty) + } + }; + + //Like the request middleware we specify the VariationContext to the default language. + _variationContextAccessor.VariationContext = new VariationContext(Cultures[0]); + GetRequiredService().EnsureUmbracoContext(); + } + + private IContentService ContentService => GetRequiredService(); + + public InstallationSummary InstallationSummary { get; set; } + + protected override void CustomTestSetup(IUmbracoBuilder builder) + { + builder.Services.AddUnique(_variationContextAccessor); + builder.AddNuCache(); + } + + private readonly TestVariationContextAccessor _variationContextAccessor = new TestVariationContextAccessor(); + + public IContent Root { get; set; } + public string[] Cultures { get; set; } + + + [Test] + public void Having_three_cultures_and_set_domain_on_all_of_them() + { + foreach (var culture in Cultures) + { + SetDomainOnContent(Root, culture, GetDomainUrlFromCultureCode(culture)); + } + + IEnumerable rootUrls = GetContentUrlsAsync(Root); + + Assert.Multiple(() => + { + Assert.AreEqual(6, rootUrls.Count()); + foreach (var culture in Cultures) + { + var domain = GetDomainUrlFromCultureCode(culture); + Assert.IsTrue(rootUrls.Any(x => x.Text == domain)); + Assert.IsTrue(rootUrls.Any(x => x.Text == "https://localhost" + domain)); + } + }); + } + + [Test] + public void Having_three_cultures_but_set_domain_on_a_non_default_language() + { + var culture = Cultures[1]; + var domain = GetDomainUrlFromCultureCode(culture); + SetDomainOnContent(Root, culture, domain); + + IEnumerable rootUrls = GetContentUrlsAsync(Root); + + Assert.Multiple(() => + { + Assert.AreEqual(4, rootUrls.Count()); + + //We expect two for the domain that is setup + Assert.IsTrue(rootUrls.Any(x => x.IsUrl && x.Text == domain && x.Culture == culture)); + Assert.IsTrue(rootUrls.Any(x => x.IsUrl && x.Text == "https://localhost" + domain && x.Culture == culture)); + + //We expect the default language to be routable on the default path "/" + Assert.IsTrue(rootUrls.Any(x=>x.IsUrl && x.Text == "/" && x.Culture == Cultures[0])); + + //We dont expect non-default languages without a domain to be routable + Assert.IsTrue(rootUrls.Any(x=>x.IsUrl == false && x.Culture == Cultures[2])); + }); + } + + private static string GetDomainUrlFromCultureCode(string culture) => + "/" + culture.Replace("-", string.Empty).ToLower() + "/"; + + private void SetDomainOnContent(IContent content, string cultureIsoCode, string domain) + { + IDomainService domainService = GetRequiredService(); + var langId = GetRequiredService().GetLanguageIdByIsoCode(cultureIsoCode); + domainService.Save( + new UmbracoDomain(domain) { RootContentId = content.Id, LanguageId = langId }); + } + + private IEnumerable GetContentUrlsAsync(IContent root) => + root.GetContentUrlsAsync( + GetRequiredService(), + GetRequiredService().GetRequiredUmbracoContext(), + GetRequiredService(), + GetRequiredService(), + ContentService, + GetRequiredService(), + GetRequiredService>(), + GetRequiredService(), + GetRequiredService() + ).GetAwaiter().GetResult(); + + } +} diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UrlAndDomains/package.xml b/tests/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UrlAndDomains/package.xml new file mode 100644 index 000000000000..d07047ecfa2d --- /dev/null +++ b/tests/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UrlAndDomains/package.xml @@ -0,0 +1,77 @@ + + + + + Test + + + + + + + + + + + TextPageLang + textPageLang + d4a44303-bf68-4f34-9f87-6668ff9e9cdc + icon-document + folder.png + + True + False + False + Culture + + + + + TextPageLang + + + textPage + textPageLang + + + + Grid + grid + 74dcad47-03e6-4190-a7d5-480bd1d96783 + Umbraco.Grid + 9ccf22c3-34c5-4e58-b365-a2d806c00540 + Content + 0 + False + False + Culture + + + + + 2074 + 1cd3a297-a821-49e9-98d8-5c21ddd2aeaf + Group + Content + content + 0 + + + + + + + + + + + + + + + + + + + + diff --git a/tests/Umbraco.Tests.UnitTests/TestHelpers/PublishedSnapshotServiceTestBase.cs b/tests/Umbraco.Tests.UnitTests/TestHelpers/PublishedSnapshotServiceTestBase.cs new file mode 100644 index 000000000000..87056eb6873e --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/TestHelpers/PublishedSnapshotServiceTestBase.cs @@ -0,0 +1,278 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.Logging; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.PropertyEditors.ValueConverters; +using Umbraco.Cms.Core.PublishedCache; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Scoping; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +using Umbraco.Cms.Core.Sync; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; +using Umbraco.Cms.Infrastructure.Serialization; +using Umbraco.Cms.Tests.Common; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Tests.UnitTests.TestHelpers +{ + [TestFixture] + public class PublishedSnapshotServiceTestBase + { + [SetUp] + public virtual void Setup() + { + VariationContextAccessor = new TestVariationContextAccessor(); + PublishedSnapshotAccessor = new TestPublishedSnapshotAccessor(); + } + + [TearDown] + public void Teardown() => SnapshotService?.Dispose(); + + protected IShortStringHelper ShortStringHelper { get; } = TestHelper.ShortStringHelper; + protected virtual IPublishedModelFactory PublishedModelFactory { get; } = new NoopPublishedModelFactory(); + protected IContentTypeService ContentTypeService { get; private set; } + protected IMediaTypeService MediaTypeService { get; private set; } + protected IDataTypeService DataTypeService { get; private set; } + protected IDomainService DomainService { get; private set; } + protected IPublishedValueFallback PublishedValueFallback { get; private set; } + protected IPublishedSnapshotService SnapshotService { get; private set; } + protected IVariationContextAccessor VariationContextAccessor { get; private set; } + protected TestPublishedSnapshotAccessor PublishedSnapshotAccessor { get; private set; } + protected TestNuCacheContentService NuCacheContentService { get; private set; } + protected PublishedContentTypeFactory PublishedContentTypeFactory { get; private set; } + protected GlobalSettings GlobalSettings { get; } = new(); + + protected virtual PropertyValueConverterCollection PropertyValueConverterCollection => + new(() => new[] { new TestSimpleTinyMceValueConverter() }); + + protected IPublishedContent GetContent(int id) + { + IPublishedSnapshot snapshot = GetPublishedSnapshot(); + IPublishedContent doc = snapshot.Content.GetById(id); + Assert.IsNotNull(doc); + return doc; + } + + protected IPublishedContent GetMedia(int id) + { + IPublishedSnapshot snapshot = GetPublishedSnapshot(); + IPublishedContent doc = snapshot.Media.GetById(id); + Assert.IsNotNull(doc); + return doc; + } + + protected UrlProvider GetUrlProvider( + IUmbracoContextAccessor umbracoContextAccessor, + RequestHandlerSettings requestHandlerSettings, + WebRoutingSettings webRoutingSettings, + out UriUtility uriUtility) + { + uriUtility = new UriUtility(Mock.Of()); + var urlProvider = new DefaultUrlProvider( + Options.Create(requestHandlerSettings), + Mock.Of>(), + new SiteDomainMapper(), + umbracoContextAccessor, + uriUtility, + Mock.Of(x=>x.GetDefaultLanguageIsoCode() == GlobalSettings.DefaultUILanguage) + ); + + var publishedUrlProvider = new UrlProvider( + umbracoContextAccessor, + Options.Create(webRoutingSettings), + new UrlProviderCollection(() => new[] { urlProvider }), + new MediaUrlProviderCollection(() => Enumerable.Empty()), + Mock.Of()); + + return publishedUrlProvider; + } + + protected static PublishedRouter CreatePublishedRouter( + IUmbracoContextAccessor umbracoContextAccessor, + IEnumerable contentFinders = null, + IPublishedUrlProvider publishedUrlProvider = null) => new(Options.Create(new WebRoutingSettings()), + new ContentFinderCollection(() => contentFinders ?? Enumerable.Empty()), + new TestLastChanceFinder(), new TestVariationContextAccessor(), Mock.Of(), + Mock.Of>(), publishedUrlProvider ?? Mock.Of(), + Mock.Of(), Mock.Of(), Mock.Of(), + Mock.Of(), umbracoContextAccessor, Mock.Of()); + + protected IUmbracoContextAccessor GetUmbracoContextAccessor(string urlAsString) + { + IPublishedSnapshot snapshot = GetPublishedSnapshot(); + + var uri = new Uri(urlAsString.Contains(Uri.SchemeDelimiter) + ? urlAsString + : $"http://example.com{urlAsString}"); + + IUmbracoContext umbracoContext = Mock.Of( + x => x.CleanedUmbracoUrl == uri + && x.Content == snapshot.Content + && x.PublishedSnapshot == snapshot); + var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); + return umbracoContextAccessor; + } + + /// + /// Used as a property editor for any test property that has an editor alias called "Umbraco.Void.RTE" + /// + private class TestSimpleTinyMceValueConverter : SimpleTinyMceValueConverter + { + public override bool IsConverter(IPublishedPropertyType propertyType) + => propertyType.EditorAlias == "Umbraco.Void.RTE"; + } + + protected static DataType[] GetDefaultDataTypes() + { + var serializer = new ConfigurationEditorJsonSerializer(); + + // create data types, property types and content types + var dataType = + new DataType(new VoidEditor("Editor", Mock.Of()), serializer) { Id = 3 }; + + return new[] { dataType }; + } + + protected virtual ServiceContext CreateServiceContext(IContentType[] contentTypes, IMediaType[] mediaTypes, + IDataType[] dataTypes) + { + var contentTypeService = new Mock(); + contentTypeService.Setup(x => x.GetAll()).Returns(contentTypes); + contentTypeService.Setup(x => x.GetAll(It.IsAny())).Returns(contentTypes); + contentTypeService.Setup(x => x.Get(It.IsAny())) + .Returns((string alias) => contentTypes.FirstOrDefault(x => x.Alias.InvariantEquals(alias))); + + var mediaTypeService = new Mock(); + mediaTypeService.Setup(x => x.GetAll()).Returns(mediaTypes); + mediaTypeService.Setup(x => x.GetAll(It.IsAny())).Returns(mediaTypes); + mediaTypeService.Setup(x => x.Get(It.IsAny())) + .Returns((string alias) => mediaTypes.FirstOrDefault(x => x.Alias.InvariantEquals(alias))); + + var contentTypeServiceBaseFactory = new Mock(); + contentTypeServiceBaseFactory.Setup(x => x.For(It.IsAny())) + .Returns(contentTypeService.Object); + + var dataTypeServiceMock = new Mock(); + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataTypes); + + return ServiceContext.CreatePartial( + dataTypeService: dataTypeServiceMock.Object, + memberTypeService: Mock.Of(), + memberService: Mock.Of(), + contentTypeService: contentTypeService.Object, + mediaTypeService: mediaTypeService.Object, + localizationService: Mock.Of(), + domainService: Mock.Of(), + fileService: Mock.Of() + ); + } + + /// + /// Creates a published snapshot and set the accessor to resolve the created one + /// + /// + protected IPublishedSnapshot GetPublishedSnapshot() + { + IPublishedSnapshot snapshot = SnapshotService.CreatePublishedSnapshot(null); + PublishedSnapshotAccessor.SetCurrent(snapshot); + return snapshot; + } + + /// + /// Initializes the with a source of data + /// + /// + /// + protected void InitializedCache( + IEnumerable contentNodeKits, + IContentType[] contentTypes, + IDataType[] dataTypes = null, + IEnumerable mediaNodeKits = null, + IMediaType[] mediaTypes = null) + { + // create a data source for NuCache + NuCacheContentService = new TestNuCacheContentService(contentNodeKits, mediaNodeKits); + + IRuntimeState runtime = Mock.Of(); + Mock.Get(runtime).Setup(x => x.Level).Returns(RuntimeLevel.Run); + + // create a service context + ServiceContext serviceContext = CreateServiceContext( + contentTypes ?? Array.Empty(), + mediaTypes ?? Array.Empty(), + dataTypes ?? GetDefaultDataTypes()); + + DataTypeService = serviceContext.DataTypeService; + ContentTypeService = serviceContext.ContentTypeService; + MediaTypeService = serviceContext.MediaTypeService; + DomainService = serviceContext.DomainService; + + // create a scope provider + IScopeProvider scopeProvider = Mock.Of(); + Mock.Get(scopeProvider) + .Setup(x => x.CreateScope( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(Mock.Of); + + // create a published content type factory + PublishedContentTypeFactory = new PublishedContentTypeFactory( + PublishedModelFactory, + PropertyValueConverterCollection, + DataTypeService); + + ITypeFinder typeFinder = TestHelper.GetTypeFinder(); + + var nuCacheSettings = new NuCacheSettings(); + + // at last, create the complete NuCache snapshot service! + var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; + SnapshotService = new PublishedSnapshotService( + options, + Mock.Of(x => x.GetSyncBootState() == SyncBootState.WarmBoot), + new SimpleMainDom(), + serviceContext, + PublishedContentTypeFactory, + PublishedSnapshotAccessor, + VariationContextAccessor, + Mock.Of(), + NullLoggerFactory.Instance, + scopeProvider, + NuCacheContentService, + new TestDefaultCultureAccessor(), + Options.Create(GlobalSettings), + PublishedModelFactory, + TestHelper.GetHostingEnvironment(), + Options.Create(nuCacheSettings), + //ContentNestedDataSerializerFactory, + new ContentDataSerializer(new DictionaryOfPropertyDataSerializer())); + + // invariant is the current default + VariationContextAccessor.VariationContext = new VariationContext(); + + PublishedValueFallback = new PublishedValueFallback(serviceContext, VariationContextAccessor); + } + } +} diff --git a/tests/Umbraco.Tests.UnitTests/TestHelpers/TestNuCacheContentService.cs b/tests/Umbraco.Tests.UnitTests/TestHelpers/TestNuCacheContentService.cs new file mode 100644 index 000000000000..25542c5203dd --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/TestHelpers/TestNuCacheContentService.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Infrastructure.PublishedCache.Persistence; + +namespace Umbraco.Cms.Tests.UnitTests.TestHelpers +{ + public class TestNuCacheContentService : INuCacheContentService + { + private IPublishedModelFactory PublishedModelFactory { get; } = new NoopPublishedModelFactory(); + + public TestNuCacheContentService(params ContentNodeKit[] kits) + : this((IEnumerable)kits) + { } + + public TestNuCacheContentService(IEnumerable contentKits, IEnumerable mediaKits = null) + { + ContentKits = contentKits?.ToDictionary(x => x.Node.Id, x => x) ?? new Dictionary(); + MediaKits = mediaKits?.ToDictionary(x => x.Node.Id, x => x) ?? new Dictionary(); + } + + public Dictionary ContentKits { get; } + public Dictionary MediaKits { get; } + + // note: it is important to clone the returned kits, as the inner + // ContentNode is directly reused and modified by the snapshot service + public ContentNodeKit GetContentSource(int id) + => ContentKits.TryGetValue(id, out ContentNodeKit kit) ? kit.Clone(PublishedModelFactory) : default; + + public IEnumerable GetAllContentSources() + => ContentKits.Values + .OrderBy(x => x.Node.Level) + .ThenBy(x => x.Node.ParentContentId) + .ThenBy(x => x.Node.SortOrder) + .Select(x => x.Clone(PublishedModelFactory)); + + public IEnumerable GetBranchContentSources(int id) + => ContentKits.Values + .Where(x => x.Node.Path.EndsWith("," + id) || x.Node.Path.Contains("," + id + ",")) + .OrderBy(x => x.Node.Level) + .ThenBy(x => x.Node.ParentContentId) + .ThenBy(x => x.Node.SortOrder) + .Select(x => x.Clone(PublishedModelFactory)); + + public IEnumerable GetTypeContentSources(IEnumerable ids) + => ContentKits.Values + .Where(x => ids.Contains(x.ContentTypeId)) + .OrderBy(x => x.Node.Level) + .ThenBy(x => x.Node.ParentContentId) + .ThenBy(x => x.Node.SortOrder) + .Select(x => x.Clone(PublishedModelFactory)); + + public ContentNodeKit GetMediaSource(int id) + => MediaKits.TryGetValue(id, out ContentNodeKit kit) ? kit.Clone(PublishedModelFactory) : default; + + public IEnumerable GetAllMediaSources() + => MediaKits.Values + .OrderBy(x => x.Node.Level) + .ThenBy(x => x.Node.ParentContentId) + .ThenBy(x => x.Node.SortOrder) + .Select(x => x.Clone(PublishedModelFactory)); + + public IEnumerable GetBranchMediaSources(int id) + => MediaKits.Values + .Where(x => x.Node.Path.EndsWith("," + id) || x.Node.Path.Contains("," + id + ",")) + .OrderBy(x => x.Node.Level) + .ThenBy(x => x.Node.ParentContentId) + .ThenBy(x => x.Node.SortOrder) + .Select(x => x.Clone(PublishedModelFactory)); + + public IEnumerable GetTypeMediaSources(IEnumerable ids) + => MediaKits.Values + .Where(x => ids.Contains(x.ContentTypeId)) + .OrderBy(x => x.Node.Level) + .ThenBy(x => x.Node.ParentContentId) + .ThenBy(x => x.Node.SortOrder) + .Select(x => x.Clone(PublishedModelFactory)); + + public void DeleteContentItem(IContentBase item) => throw new NotImplementedException(); + public void DeleteContentItems(IEnumerable items) => throw new NotImplementedException(); + public void RefreshContent(IContent content) => throw new NotImplementedException(); + + public void RebuildDatabaseCacheIfSerializerChanged() => throw new NotImplementedException(); + public void RefreshMedia(IMedia media) => throw new NotImplementedException(); + public void RefreshMember(IMember member) => throw new NotImplementedException(); + public void Rebuild(IReadOnlyCollection contentTypeIds = null, IReadOnlyCollection mediaTypeIds = null, IReadOnlyCollection memberTypeIds = null) => throw new NotImplementedException(); + + public bool VerifyContentDbCache() => throw new NotImplementedException(); + public bool VerifyMediaDbCache() => throw new NotImplementedException(); + public bool VerifyMemberDbCache() => throw new NotImplementedException(); + } +} diff --git a/tests/Umbraco.Tests/Collections/StackQueueTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Collections/StackQueueTests.cs similarity index 93% rename from tests/Umbraco.Tests/Collections/StackQueueTests.cs rename to tests/Umbraco.Tests.UnitTests/Umbraco.Core/Collections/StackQueueTests.cs index 52d0370f0dfe..4caf7bd00536 100644 --- a/tests/Umbraco.Tests/Collections/StackQueueTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Collections/StackQueueTests.cs @@ -1,7 +1,7 @@ -using NUnit.Framework; +using NUnit.Framework; using Umbraco.Core.Collections; -namespace Umbraco.Tests.Collections +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Collections { [TestFixture] public class StackQueueTests @@ -16,7 +16,7 @@ public void Queue() } var expected = 0; - while(sq.Count > 0) + while (sq.Count > 0) { var next = sq.Dequeue(); Assert.AreEqual(expected, next); diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByAliasTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByAliasTests.cs new file mode 100644 index 000000000000..0cdbce3da85b --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByAliasTests.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Logging; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; +using Umbraco.Extensions; +using Constants = Umbraco.Cms.Core.Constants; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing +{ + // TODO: We should be able to decouple this from the base db tests since we're just mocking the services now + + [TestFixture] + public class ContentFinderByAliasTests : UrlRoutingTestBase + { + + [TestCase("/this/is/my/alias", 1001)] + [TestCase("/anotheralias", 1001)] + [TestCase("/page2/alias", 10011)] + [TestCase("/2ndpagealias", 10011)] + [TestCase("/only/one/alias", 100111)] + [TestCase("/ONLY/one/Alias", 100111)] + [TestCase("/alias43", 100121)] + public async Task Lookup_By_Url_Alias(string urlAsString, int nodeMatch) + { + var umbracoContextAccessor = GetUmbracoContextAccessor(urlAsString); + var publishedRouter = CreatePublishedRouter(umbracoContextAccessor); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + + var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); + var lookup = + new ContentFinderByUrlAlias(Mock.Of>(), Mock.Of(), VariationContextAccessor, umbracoContextAccessor); + + var result = lookup.TryFindContent(frequest); + + Assert.IsTrue(result); + Assert.AreEqual(frequest.PublishedContent.Id, nodeMatch); + } + } +} diff --git a/tests/Umbraco.Tests/Routing/ContentFinderByAliasWithDomainsTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByAliasWithDomainsTests.cs similarity index 52% rename from tests/Umbraco.Tests/Routing/ContentFinderByAliasWithDomainsTests.cs rename to tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByAliasWithDomainsTests.cs index 587000010737..8b77c4859930 100644 --- a/tests/Umbraco.Tests/Routing/ContentFinderByAliasWithDomainsTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByAliasWithDomainsTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -8,40 +9,18 @@ using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; +using Umbraco.Extensions; using Constants = Umbraco.Cms.Core.Constants; -namespace Umbraco.Tests.Routing +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing { [TestFixture] - public class ContentFinderByAliasWithDomainsTests : ContentFinderByAliasTests + public class ContentFinderByAliasWithDomainsTests : UrlRoutingTestBase { - private PublishedContentType _publishedContentType; - protected override void Initialize() - { - base.Initialize(); - - var properties = new[] - { - new PublishedPropertyType( - propertyTypeAlias:"umbracoUrlAlias", - dataTypeId: Constants.DataTypes.Textbox, - isUserProperty:false, - variations: ContentVariation.Nothing, - propertyValueConverters:new PropertyValueConverterCollection(Enumerable.Empty()), - contentType:Mock.Of(), - publishedModelFactory:Mock.Of(), - factory:Mock.Of() - ) - }; - _publishedContentType = new PublishedContentType(Guid.NewGuid(), 0, "Doc", PublishedItemType.Content, Enumerable.Empty(), properties, ContentVariation.Nothing); - } - - protected override PublishedContentType GetPublishedContentTypeByAlias(string alias) - { - if (alias == "Doc") return _publishedContentType; - return null; - } [TestCase("http://domain1.com/this/is/my/alias", "de-DE", -1001)] // alias to domain's page fails - no alias on domain's home [TestCase("http://domain1.com/page2/alias", "de-DE", 10011)] // alias to sub-page works @@ -56,10 +35,11 @@ protected override PublishedContentType GetPublishedContentTypeByAlias(string al public async Task Lookup_By_Url_Alias_And_Domain(string inputUrl, string expectedCulture, int expectedNode) { //SetDomains1(); + var umbracoContextAccessor = GetUmbracoContextAccessor(inputUrl); + var publishedRouter = CreatePublishedRouter(umbracoContextAccessor); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); - var umbracoContext = GetUmbracoContext(inputUrl); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext)); - var request = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); + var request = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); // must lookup domain publishedRouter.FindDomain(request); @@ -68,7 +48,7 @@ public async Task Lookup_By_Url_Alias_And_Domain(string inputUrl, string expecte Assert.AreEqual(expectedCulture, request.Culture); } - var finder = new ContentFinderByUrlAlias(LoggerFactory.CreateLogger(), Mock.Of(), VariationContextAccessor, GetUmbracoContextAccessor(umbracoContext)); + var finder = new ContentFinderByUrlAlias(Mock.Of>(), Mock.Of(), VariationContextAccessor, umbracoContextAccessor); var result = finder.TryFindContent(request); if (expectedNode > 0) diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByIdTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByIdTests.cs new file mode 100644 index 000000000000..1e5d95f42e01 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByIdTests.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing +{ + [TestFixture] + public class ContentFinderByIdTests : PublishedSnapshotServiceTestBase + { + [SetUp] + public override void Setup() + { + base.Setup(); + + string xml = PublishedContentXml.BaseWebTestXml(1234); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + + } + + [TestCase("/1046", 1046)] + public async Task Lookup_By_Id(string urlAsString, int nodeMatch) + { + var umbracoContextAccessor = GetUmbracoContextAccessor(urlAsString); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + var publishedRouter = CreatePublishedRouter(umbracoContextAccessor); + var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); + var webRoutingSettings = new WebRoutingSettings(); + var lookup = new ContentFinderByIdPath(Options.Create(webRoutingSettings), Mock.Of>(), Mock.Of(), umbracoContextAccessor); + + + var result = lookup.TryFindContent(frequest); + + Assert.IsTrue(result); + Assert.AreEqual(frequest.PublishedContent.Id, nodeMatch); + } + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByPageIdQueryTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByPageIdQueryTests.cs new file mode 100644 index 000000000000..9aceaf766a63 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByPageIdQueryTests.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Web; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing +{ + [TestFixture] + public class ContentFinderByPageIdQueryTests : PublishedSnapshotServiceTestBase + { + [SetUp] + public override void Setup() + { + base.Setup(); + + string xml = PublishedContentXml.BaseWebTestXml(1234); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + + } + + [TestCase("/?umbPageId=1046", 1046)] + [TestCase("/?UMBPAGEID=1046", 1046)] + [TestCase("/default.aspx?umbPageId=1046", 1046)] // TODO: Should this match?? + [TestCase("/some/other/page?umbPageId=1046", 1046)] // TODO: Should this match?? + [TestCase("/some/other/page.aspx?umbPageId=1046", 1046)] // TODO: Should this match?? + public async Task Lookup_By_Page_Id(string urlAsString, int nodeMatch) + { + var umbracoContextAccessor = GetUmbracoContextAccessor(urlAsString); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + var publishedRouter = CreatePublishedRouter(umbracoContextAccessor); + var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); + + var queryStrings = HttpUtility.ParseQueryString(umbracoContext.CleanedUmbracoUrl.Query); + + var mockRequestAccessor = new Mock(); + mockRequestAccessor.Setup(x => x.GetRequestValue("umbPageID")) + .Returns(queryStrings["umbPageID"]); + + var lookup = new ContentFinderByPageIdQuery(mockRequestAccessor.Object, umbracoContextAccessor); + + var result = lookup.TryFindContent(frequest); + + Assert.IsTrue(result); + Assert.AreEqual(frequest.PublishedContent.Id, nodeMatch); + } + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByUrlAndTemplateTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByUrlAndTemplateTests.cs new file mode 100644 index 000000000000..58bcbbefb4b8 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByUrlAndTemplateTests.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.Common.Testing; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing +{ + [TestFixture] + public class ContentFinderByUrlAndTemplateTests : PublishedSnapshotServiceTestBase + { + private IFileService _fileService; + + [SetUp] + public override void Setup() + { + base.Setup(); + + string xml = PublishedContentXml.BaseWebTestXml(1234); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + } + + protected override ServiceContext CreateServiceContext(IContentType[] contentTypes, IMediaType[] mediaTypes, IDataType[] dataTypes) + { + var serviceContext = base.CreateServiceContext(contentTypes, mediaTypes, dataTypes); + + var fileService = Mock.Get(serviceContext.FileService); + fileService.Setup(x => x.GetTemplate(It.IsAny())) + .Returns((string alias) => new Template(ShortStringHelper, alias, alias)); + + _fileService = fileService.Object; + + return serviceContext; + } + + [TestCase("/blah")] + [TestCase("/home/Sub1/blah")] + [TestCase("/Home/Sub1/Blah")] //different cases + public async Task Match_Document_By_Url_With_Template(string urlAsString) + { + GlobalSettings.HideTopLevelNodeFromPath = false; + + var umbracoContextAccessor = GetUmbracoContextAccessor(urlAsString); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + var publishedRouter = CreatePublishedRouter(umbracoContextAccessor); + var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); + + var webRoutingSettings = new WebRoutingSettings(); + var lookup = new ContentFinderByUrlAndTemplate( + Mock.Of>(), + _fileService, + ContentTypeService, + umbracoContextAccessor, + Microsoft.Extensions.Options.Options.Create(webRoutingSettings)); + + var result = lookup.TryFindContent(frequest); + + IPublishedRequest request = frequest.Build(); + + Assert.IsTrue(result); + Assert.IsNotNull(frequest.PublishedContent); + var templateAlias = request.GetTemplateAlias(); + Assert.IsNotNull(templateAlias); + Assert.AreEqual("blah".ToUpperInvariant(), templateAlias.ToUpperInvariant()); + } + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByUrlTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByUrlTests.cs new file mode 100644 index 000000000000..556eed962274 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByUrlTests.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; +using Umbraco.Extensions; + + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing +{ + [TestFixture] + public class ContentFinderByUrlTests : PublishedSnapshotServiceTestBase + { + private async Task<(ContentFinderByUrl finder, IPublishedRequestBuilder frequest)> GetContentFinder(string urlString) + { + string xml = PublishedContentXml.BaseWebTestXml(1234); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + + var umbracoContextAccessor = GetUmbracoContextAccessor(urlString); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + var publishedRouter = CreatePublishedRouter(umbracoContextAccessor); + var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); + var lookup = new ContentFinderByUrl(Mock.Of>(), umbracoContextAccessor); + return (lookup, frequest); + } + + [TestCase("/", 1046)] + [TestCase("/Sub1", 1173)] + [TestCase("/sub1", 1173)] + [TestCase("/home/sub1", -1)] // should fail + + // these two are special. getNiceUrl(1046) returns "/" but getNiceUrl(1172) cannot also return "/" so + // we've made it return "/test-page" => we have to support that URL back in the lookup... + [TestCase("/home", 1046)] + [TestCase("/test-page", 1172)] + public async Task Match_Document_By_Url_Hide_Top_Level(string urlString, int expectedId) + { + GlobalSettings.HideTopLevelNodeFromPath = true; + + var lookup = await GetContentFinder(urlString); + + Assert.IsTrue(GlobalSettings.HideTopLevelNodeFromPath); + + // FIXME: debugging - going further down, the routes cache is NOT empty?! + if (urlString == "/home/sub1") + System.Diagnostics.Debugger.Break(); + + var result = lookup.finder.TryFindContent(lookup.frequest); + + if (expectedId > 0) + { + Assert.IsTrue(result); + Assert.AreEqual(expectedId, lookup.frequest.PublishedContent.Id); + } + else + { + Assert.IsFalse(result); + } + } + + [TestCase("/", 1046)] + [TestCase("/home", 1046)] + [TestCase("/home/Sub1", 1173)] + [TestCase("/Home/Sub1", 1173)] //different cases + public async Task Match_Document_By_Url(string urlString, int expectedId) + { + GlobalSettings.HideTopLevelNodeFromPath = false; + + var lookup = await GetContentFinder(urlString); + + Assert.IsFalse(GlobalSettings.HideTopLevelNodeFromPath); + + var result = lookup.finder.TryFindContent(lookup.frequest); + + Assert.IsTrue(result); + Assert.AreEqual(expectedId, lookup.frequest.PublishedContent.Id); + } + /// + /// This test handles requests with special characters in the URL. + /// + /// + /// + [TestCase("/", 1046)] + [TestCase("/home/sub1/custom-sub-3-with-accént-character", 1179)] + [TestCase("/home/sub1/custom-sub-4-with-æøå", 1180)] + public async Task Match_Document_By_Url_With_Special_Characters(string urlString, int expectedId) + { + GlobalSettings.HideTopLevelNodeFromPath = false; + + var lookup = await GetContentFinder(urlString); + + var result = lookup.finder.TryFindContent(lookup.frequest); + + Assert.IsTrue(result); + Assert.AreEqual(expectedId, lookup.frequest.PublishedContent.Id); + } + + /// + /// This test handles requests with a hostname associated. + /// The logic for handling this goes through the DomainHelper and is a bit different + /// from what happens in a normal request - so it has a separate test with a mocked + /// hostname added. + /// + /// + /// + [TestCase("/", 1046)] + [TestCase("/home/sub1/custom-sub-3-with-accént-character", 1179)] + [TestCase("/home/sub1/custom-sub-4-with-æøå", 1180)] + public async Task Match_Document_By_Url_With_Special_Characters_Using_Hostname(string urlString, int expectedId) + { + GlobalSettings.HideTopLevelNodeFromPath = false; + + var lookup = await GetContentFinder(urlString); + + lookup.frequest.SetDomain(new DomainAndUri(new Domain(1, "mysite", -1, "en-US", false), new Uri("http://mysite/"))); + + var result = lookup.finder.TryFindContent(lookup.frequest); + + Assert.IsTrue(result); + Assert.AreEqual(expectedId, lookup.frequest.PublishedContent.Id); + } + + /// + /// This test handles requests with a hostname with special characters associated. + /// The logic for handling this goes through the DomainHelper and is a bit different + /// from what happens in a normal request - so it has a separate test with a mocked + /// hostname added. + /// + /// + /// + [TestCase("/æøå/", 1046)] + [TestCase("/æøå/home/sub1", 1173)] + [TestCase("/æøå/home/sub1/custom-sub-3-with-accént-character", 1179)] + [TestCase("/æøå/home/sub1/custom-sub-4-with-æøå", 1180)] + public async Task Match_Document_By_Url_With_Special_Characters_In_Hostname(string urlString, int expectedId) + { + GlobalSettings.HideTopLevelNodeFromPath = false; + + var lookup = await GetContentFinder(urlString); + + lookup.frequest.SetDomain(new DomainAndUri(new Domain(1, "mysite/æøå", -1, "en-US", false), new Uri("http://mysite/æøå"))); + + var result = lookup.finder.TryFindContent(lookup.frequest); + + Assert.IsTrue(result); + Assert.AreEqual(expectedId, lookup.frequest.PublishedContent.Id); + } + } +} diff --git a/tests/Umbraco.Tests/Routing/ContentFinderByUrlWithDomainsTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByUrlWithDomainsTests.cs similarity index 83% rename from tests/Umbraco.Tests/Routing/ContentFinderByUrlWithDomainsTests.cs rename to tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByUrlWithDomainsTests.cs index f9ea04a2886b..d99214038649 100644 --- a/tests/Umbraco.Tests/Routing/ContentFinderByUrlWithDomainsTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByUrlWithDomainsTests.cs @@ -1,42 +1,47 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Moq; using NUnit.Framework; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Routing; +using Umbraco.Extensions; -namespace Umbraco.Tests.Routing +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing { [TestFixture] public class ContentFinderByUrlWithDomainsTests : UrlRoutingTestBase { - void SetDomains3() + private void SetDomains3() { - SetupDomainServiceMock(new[] - { - new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangDeId, RootContentId = 1001, LanguageIsoCode = "de-DE"} - }); + var domainService = Mock.Get(DomainService); + domainService.Setup(service => service.GetAll(It.IsAny())) + .Returns((bool incWildcards) => new[] + { + new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangDeId, RootContentId = 1001, LanguageIsoCode = "de-DE"} + }); } - void SetDomains4() + private void SetDomains4() { - SetupDomainServiceMock(new[] - { - new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"}, - new UmbracoDomain("domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}, - new UmbracoDomain("domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"}, - new UmbracoDomain("http://domain3.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1003, LanguageIsoCode = "en-US"}, - new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"}, - new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"} - }); - + var domainService = Mock.Get(DomainService); + + domainService.Setup(service => service.GetAll(It.IsAny())) + .Returns((bool incWildcards) => new[] + { + new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"}, + new UmbracoDomain("domain1.com/en") {Id = 2, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}, + new UmbracoDomain("domain1.com/fr") {Id = 3, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"}, + new UmbracoDomain("http://domain3.com/") {Id = 4, LanguageId = LangEngId, RootContentId = 1003, LanguageIsoCode = "en-US"}, + new UmbracoDomain("http://domain3.com/en") {Id = 5, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"}, + new UmbracoDomain("http://domain3.com/fr") {Id = 6, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"} + }); } protected override string GetXmlContent(int templateId) - { - return @" + => @" @@ -115,7 +120,6 @@ protected override string GetXmlContent(int templateId) "; - } [TestCase("http://domain1.com/", 1001)] [TestCase("http://domain1.com/1001-1", 10011)] @@ -125,16 +129,17 @@ public async Task Lookup_SingleDomain(string url, int expectedId) { SetDomains3(); - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = true }; + GlobalSettings.HideTopLevelNodeFromPath = true; - var umbracoContext = GetUmbracoContext(url, globalSettings:globalSettings); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext), Factory); + var umbracoContextAccessor = GetUmbracoContextAccessor(url); + var publishedRouter = CreatePublishedRouter(umbracoContextAccessor); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); // must lookup domain else lookup by URL fails publishedRouter.FindDomain(frequest); - var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger(), GetUmbracoContextAccessor(umbracoContext)); + var lookup = new ContentFinderByUrl(Mock.Of>(), umbracoContextAccessor); var result = lookup.TryFindContent(frequest); Assert.IsTrue(result); Assert.AreEqual(expectedId, frequest.PublishedContent.Id); @@ -164,19 +169,20 @@ public async Task Lookup_NestedDomains(string url, int expectedId, string expect SetDomains4(); // defaults depend on test environment - expectedCulture = expectedCulture ?? System.Threading.Thread.CurrentThread.CurrentUICulture.Name; + expectedCulture ??= System.Threading.Thread.CurrentThread.CurrentUICulture.Name; - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = true }; + GlobalSettings.HideTopLevelNodeFromPath = true; - var umbracoContext = GetUmbracoContext(url, globalSettings:globalSettings); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext), Factory); - var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); + var umbracoContextAccessor = GetUmbracoContextAccessor(url); + var publishedRouter = CreatePublishedRouter(umbracoContextAccessor); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); // must lookup domain else lookup by URL fails publishedRouter.FindDomain(frequest); Assert.AreEqual(expectedCulture, frequest.Culture); - var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger(), GetUmbracoContextAccessor(umbracoContext)); + var lookup = new ContentFinderByUrl(Mock.Of>(), umbracoContextAccessor); var result = lookup.TryFindContent(frequest); Assert.IsTrue(result); Assert.AreEqual(expectedId, frequest.PublishedContent.Id); diff --git a/tests/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/DomainsAndCulturesTests.cs similarity index 72% rename from tests/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs rename to tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/DomainsAndCulturesTests.cs index 73a88abfabb9..ccaeee9322bd 100644 --- a/tests/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/DomainsAndCulturesTests.cs @@ -1,124 +1,151 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Moq; using NUnit.Framework; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Routing; +using Umbraco.Extensions; -namespace Umbraco.Tests.Routing +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing { [TestFixture] - internal class DomainsAndCulturesTests : UrlRoutingTestBase + public class DomainsAndCulturesTests : UrlRoutingTestBase { - protected override void Compose() + private void SetDomains1() { - base.Compose(); + var domainService = Mock.Get(DomainService); - Builder.Services.AddTransient(); + domainService.Setup(service => service.GetAll(It.IsAny())) + .Returns((bool incWildcards) => new[] + { + new UmbracoDomain("domain1.com/") + { + Id = 1, + LanguageId = LangDeId, + RootContentId = 1001, + LanguageIsoCode = "de-DE" + }, + new UmbracoDomain("domain1.com/en") + { + Id = 2, + LanguageId = LangEngId, + RootContentId = 10011, + LanguageIsoCode = "en-US" + }, + new UmbracoDomain("domain1.com/fr") + { + Id = 3, + LanguageId = LangFrId, + RootContentId = 10012, + LanguageIsoCode = "fr-FR" + } + }); } - private void SetDomains1() + private void SetDomains2() { - SetupDomainServiceMock(new[] - { - new UmbracoDomain("domain1.com/") - { - Id = 1, - LanguageId = LangDeId, - RootContentId = 1001, - LanguageIsoCode = "de-DE" - }, - new UmbracoDomain("domain1.com/en") - { - Id = 1, - LanguageId = LangEngId, - RootContentId = 10011, - LanguageIsoCode = "en-US" - }, - new UmbracoDomain("domain1.com/fr") + var domainService = Mock.Get(DomainService); + + domainService.Setup(service => service.GetAll(It.IsAny())) + .Returns((bool incWildcards) => new[] { - Id = 1, - LanguageId = LangFrId, - RootContentId = 10012, - LanguageIsoCode = "fr-FR" - } - }); + new UmbracoDomain("domain1.com/") + { + Id = 1, + LanguageId = LangDeId, + RootContentId = 1001, + LanguageIsoCode = "de-DE" + }, + new UmbracoDomain("domain1.com/en") + { + Id = 2, + LanguageId = LangEngId, + RootContentId = 10011, + LanguageIsoCode = "en-US" + }, + new UmbracoDomain("domain1.com/fr") + { + Id = 3, + LanguageId = LangFrId, + RootContentId = 10012, + LanguageIsoCode = "fr-FR" + }, + new UmbracoDomain("*1001") + { + Id = 4, + LanguageId = LangDeId, + RootContentId = 1001, + LanguageIsoCode = "de-DE" + }, + new UmbracoDomain("*10011") + { + Id = 5, + LanguageId = LangCzId, + RootContentId = 10011, + LanguageIsoCode = "cs-CZ" + }, + new UmbracoDomain("*100112") + { + Id = 6, + LanguageId = LangNlId, + RootContentId = 100112, + LanguageIsoCode = "nl-NL" + }, + new UmbracoDomain("*1001122") + { + Id = 7, + LanguageId = LangDkId, + RootContentId = 1001122, + LanguageIsoCode = "da-DK" + }, + new UmbracoDomain("*10012") + { + Id = 8, + LanguageId = LangNlId, + RootContentId = 10012, + LanguageIsoCode = "nl-NL" + }, + new UmbracoDomain("*10031") + { + Id = 9, + LanguageId = LangNlId, + RootContentId =10031, + LanguageIsoCode = "nl-NL" + } + }); } - private void SetDomains2() + // domains such as "/en" are natively supported, and when instanciating + // DomainAndUri for them, the host will come from the current request + // + private void SetDomains3() { - SetupDomainServiceMock(new[] - { - new UmbracoDomain("domain1.com/") - { - Id = 1, - LanguageId = LangDeId, - RootContentId = 1001, - LanguageIsoCode = "de-DE" - }, - new UmbracoDomain("domain1.com/en") - { - Id = 1, - LanguageId = LangEngId, - RootContentId = 10011, - LanguageIsoCode = "en-US" - }, - new UmbracoDomain("domain1.com/fr") - { - Id = 1, - LanguageId = LangFrId, - RootContentId = 10012, - LanguageIsoCode = "fr-FR" - }, - new UmbracoDomain("*1001") - { - Id = 1, - LanguageId = LangDeId, - RootContentId = 1001, - LanguageIsoCode = "de-DE" - }, - new UmbracoDomain("*10011") - { - Id = 1, - LanguageId = LangCzId, - RootContentId = 10011, - LanguageIsoCode = "cs-CZ" - }, - new UmbracoDomain("*100112") - { - Id = 1, - LanguageId = LangNlId, - RootContentId = 100112, - LanguageIsoCode = "nl-NL" - }, - new UmbracoDomain("*1001122") - { - Id = 1, - LanguageId = LangDkId, - RootContentId = 1001122, - LanguageIsoCode = "da-DK" - }, - new UmbracoDomain("*10012") - { - Id = 1, - LanguageId = LangNlId, - RootContentId = 10012, - LanguageIsoCode = "nl-NL" - }, - new UmbracoDomain("*10031") + var domainService = Mock.Get(DomainService); + + domainService.Setup(service => service.GetAll(It.IsAny())) + .Returns((bool incWildcards) => new[] { - Id = 1, - LanguageId = LangNlId, - RootContentId =10031, - LanguageIsoCode = "nl-NL" - } - }); + new UmbracoDomain("/en") + { + Id = 1, + LanguageId = LangEngId, + RootContentId = 10011, + LanguageIsoCode = "en-US" + }, + new UmbracoDomain("/fr") + { + Id = 2, + LanguageId = LangFrId, + RootContentId = 10012, + LanguageIsoCode = "fr-FR" + } + }); } protected override string GetXmlContent(int templateId) - { - return @" + => @" @@ -250,7 +277,6 @@ protected override string GetXmlContent(int templateId) "; - } #region Cases [TestCase("http://domain1.com/", "de-DE", 1001)] @@ -265,18 +291,19 @@ public async Task DomainAndCulture(string inputUrl, string expectedCulture, int { SetDomains1(); - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; + GlobalSettings.HideTopLevelNodeFromPath = false; - var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext), Factory); - var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); + var umbracoContextAccessor = GetUmbracoContextAccessor(inputUrl); + var publishedRouter = CreatePublishedRouter(umbracoContextAccessor); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); // lookup domain publishedRouter.FindDomain(frequest); Assert.AreEqual(expectedCulture, frequest.Culture); - var finder = new ContentFinderByUrl(LoggerFactory.CreateLogger(), GetUmbracoContextAccessor(umbracoContext)); + var finder = new ContentFinderByUrl(Mock.Of>(), umbracoContextAccessor); var result = finder.TryFindContent(frequest); Assert.IsTrue(result); @@ -311,19 +338,20 @@ public async Task DomainAndCultureWithWildcards(string inputUrl, string expected SetDomains2(); // defaults depend on test environment - expectedCulture = expectedCulture ?? System.Threading.Thread.CurrentThread.CurrentUICulture.Name; + expectedCulture ??= System.Threading.Thread.CurrentThread.CurrentUICulture.Name; - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; + GlobalSettings.HideTopLevelNodeFromPath = false; - var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext), Factory); - var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); + var umbracoContextAccessor = GetUmbracoContextAccessor(inputUrl); + var publishedRouter = CreatePublishedRouter(umbracoContextAccessor); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); // lookup domain publishedRouter.FindDomain(frequest); // find document - var finder = new ContentFinderByUrl(LoggerFactory.CreateLogger(), GetUmbracoContextAccessor(umbracoContext)); + var finder = new ContentFinderByUrl(Mock.Of>(), umbracoContextAccessor); var result = finder.TryFindContent(frequest); // apply wildcard domain @@ -333,29 +361,7 @@ public async Task DomainAndCultureWithWildcards(string inputUrl, string expected Assert.AreEqual(expectedCulture, frequest.Culture); Assert.AreEqual(frequest.PublishedContent.Id, expectedNode); } - // domains such as "/en" are natively supported, and when instanciating - // DomainAndUri for them, the host will come from the current request - // - private void SetDomains3() - { - SetupDomainServiceMock(new[] - { - new UmbracoDomain("/en") - { - Id = 1, - LanguageId = LangEngId, - RootContentId = 10011, - LanguageIsoCode = "en-US" - }, - new UmbracoDomain("/fr") - { - Id = 1, - LanguageId = LangFrId, - RootContentId = 10012, - LanguageIsoCode = "fr-FR" - } - }); - } + #region Cases [TestCase("http://domain1.com/en", "en-US", 10011)] @@ -367,10 +373,13 @@ public async Task DomainGeneric(string inputUrl, string expectedCulture, int exp { SetDomains3(); - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; - var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext), Factory); - var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); + GlobalSettings.HideTopLevelNodeFromPath = false; + + + var umbracoContextAccessor = GetUmbracoContextAccessor(inputUrl); + var publishedRouter = CreatePublishedRouter(umbracoContextAccessor); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); // lookup domain publishedRouter.FindDomain(frequest); @@ -378,7 +387,7 @@ public async Task DomainGeneric(string inputUrl, string expectedCulture, int exp Assert.AreEqual(expectedCulture, frequest.Culture); - var finder = new ContentFinderByUrl(LoggerFactory.CreateLogger(), GetUmbracoContextAccessor(umbracoContext)); + var finder = new ContentFinderByUrl(Mock.Of>(), umbracoContextAccessor); var result = finder.TryFindContent(frequest); Assert.IsTrue(result); diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/GetContentUrlsTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/GetContentUrlsTests.cs new file mode 100644 index 000000000000..f54442e4675d --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/GetContentUrlsTests.cs @@ -0,0 +1,216 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common.Builders; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing +{ + [TestFixture] + public class GetContentUrlsTests : PublishedSnapshotServiceTestBase + { + private WebRoutingSettings _webRoutingSettings; + private RequestHandlerSettings _requestHandlerSettings; + + [SetUp] + public override void Setup() + { + base.Setup(); + + _webRoutingSettings = new WebRoutingSettings(); + _requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; + + GlobalSettings.HideTopLevelNodeFromPath = false; + + string xml = PublishedContentXml.BaseWebTestXml(1234); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + } + + private ILocalizedTextService GetTextService() + { + var textService = new Mock(); + textService.Setup(x => x.Localize( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny>() + )) + .Returns((string key, string alias, CultureInfo culture, IDictionary args) + => $"{key}/{alias}"); + + return textService.Object; + } + + private ILocalizationService GetLangService(params string[] isoCodes) + { + var allLangs = isoCodes + .Select(CultureInfo.GetCultureInfo) + .Select(culture => new Language(GlobalSettings, culture.Name) + { + CultureName = culture.DisplayName, + IsDefault = true, + IsMandatory = true + }).ToArray(); + + + var langServiceMock = new Mock(); + langServiceMock.Setup(x => x.GetAllLanguages()).Returns(allLangs); + langServiceMock.Setup(x => x.GetDefaultLanguageIsoCode()).Returns(allLangs.First(x=>x.IsDefault).IsoCode); + + return langServiceMock.Object; + } + + [Test] + public async Task Content_Not_Published() + { + var contentType = ContentTypeBuilder.CreateBasicContentType(); + var content = ContentBuilder.CreateBasicContent(contentType); + content.Id = 1046; // FIXME: we are using this ID only because it's built into the test XML published cache + content.Path = "-1,1046"; + + var umbracoContextAccessor = GetUmbracoContextAccessor("http://localhost:8000"); + var publishedRouter = CreatePublishedRouter( + umbracoContextAccessor, + new[] { new ContentFinderByUrl(Mock.Of>(), umbracoContextAccessor) }); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, _requestHandlerSettings, _webRoutingSettings, out UriUtility uriUtility); + + var urls = (await content.GetContentUrlsAsync( + publishedRouter, + umbracoContext, + GetLangService("en-US", "fr-FR"), + GetTextService(), + Mock.Of(), + VariationContextAccessor, + Mock.Of>(), + uriUtility, + urlProvider)).ToList(); + + Assert.AreEqual(1, urls.Count); + Assert.AreEqual("content/itemNotPublished", urls[0].Text); + Assert.IsFalse(urls[0].IsUrl); + } + + [Test] + public async Task Invariant_Root_Content_Published_No_Domains() + { + var contentType = ContentTypeBuilder.CreateBasicContentType(); + var content = ContentBuilder.CreateBasicContent(contentType); + content.Id = 1046; // FIXME: we are using this ID only because it's built into the test XML published cache + content.Path = "-1,1046"; + content.Published = true; + + var umbracoContextAccessor = GetUmbracoContextAccessor("http://localhost:8000"); + var publishedRouter = CreatePublishedRouter( + umbracoContextAccessor, + new[] { new ContentFinderByUrl(Mock.Of>(), umbracoContextAccessor) }); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, _requestHandlerSettings, _webRoutingSettings, out UriUtility uriUtility); + + var urls = (await content.GetContentUrlsAsync( + publishedRouter, + umbracoContext, + GetLangService("en-US", "fr-FR"), + GetTextService(), + Mock.Of(), + VariationContextAccessor, + Mock.Of>(), + uriUtility, + urlProvider)).ToList(); + + + Assert.AreEqual(2, urls.Count); + + var enUrl = urls.First(x => x.Culture == "en-US"); + + Assert.AreEqual("/home/", enUrl.Text); + Assert.AreEqual("en-US", enUrl.Culture); + Assert.IsTrue(enUrl.IsUrl); + + var frUrl = urls.First(x => x.Culture == "fr-FR"); + + Assert.IsFalse(frUrl.IsUrl); + } + + [Test] + public async Task Invariant_Child_Content_Published_No_Domains() + { + var contentType = ContentTypeBuilder.CreateBasicContentType(); + var parent = ContentBuilder.CreateBasicContent(contentType); + parent.Id = 1046; // FIXME: we are using this ID only because it's built into the test XML published cache + parent.Name = "home"; + parent.Path = "-1,1046"; + parent.Published = true; + var child = ContentBuilder.CreateBasicContent(contentType); + child.Name = "sub1"; + child.Id = 1173; // FIXME: we are using this ID only because it's built into the test XML published cache + child.Path = "-1,1046,1173"; + child.Published = true; + + + var umbracoContextAccessor = GetUmbracoContextAccessor("http://localhost:8000"); + var publishedRouter = CreatePublishedRouter( + umbracoContextAccessor, + new[] { new ContentFinderByUrl(Mock.Of>(), umbracoContextAccessor) }); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + + + var localizationService = GetLangService("en-US", "fr-FR"); + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, _requestHandlerSettings, _webRoutingSettings, out UriUtility uriUtility); + + var urls = (await child.GetContentUrlsAsync( + publishedRouter, + umbracoContext, + localizationService, + GetTextService(), + Mock.Of(), + VariationContextAccessor, + Mock.Of>(), + uriUtility, + urlProvider)).ToList(); + + Assert.AreEqual(2, urls.Count); + + var enUrl = urls.First(x => x.Culture == "en-US"); + + Assert.AreEqual("/home/sub1/", enUrl.Text); + Assert.AreEqual("en-US", enUrl.Culture); + Assert.IsTrue(enUrl.IsUrl); + + var frUrl = urls.First(x => x.Culture == "fr-FR"); + + Assert.IsFalse(frUrl.IsUrl); + } + + // TODO: We need a lot of tests here, the above was just to get started with being able to unit test this method + // * variant URLs without domains assigned, what happens? + // * variant URLs with domains assigned, but also having more languages installed than there are domains/cultures assigned + // * variant URLs with an ancestor culture unpublished + // * invariant URLs with ancestors as variants + // * ... probably a lot more + + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/PublishedRouterTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/PublishedRouterTests.cs new file mode 100644 index 000000000000..b1db80232a2b --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/PublishedRouterTests.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Logging; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Tests.Common; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing +{ + [TestFixture] + public class PublishedRouterTests + { + private PublishedRouter CreatePublishedRouter(IUmbracoContextAccessor umbracoContextAccessor) + => new PublishedRouter( + Microsoft.Extensions.Options.Options.Create(new WebRoutingSettings()), + new ContentFinderCollection(() => Enumerable.Empty()), + new TestLastChanceFinder(), + new TestVariationContextAccessor(), + Mock.Of(), + Mock.Of>(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + umbracoContextAccessor, + Mock.Of()); + + private IUmbracoContextAccessor GetUmbracoContextAccessor() + { + var uri = new Uri("http://example.com"); + var umbracoContext = Mock.Of(x => x.CleanedUmbracoUrl == uri); + var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); + return umbracoContextAccessor; + } + + [Test] + public async Task ConfigureRequest_Returns_False_Without_HasPublishedContent() + { + var umbracoContextAccessor = GetUmbracoContextAccessor(); + var publishedRouter = CreatePublishedRouter(umbracoContextAccessor); + var request = await publishedRouter.CreateRequestAsync(umbracoContextAccessor.GetRequiredUmbracoContext().CleanedUmbracoUrl); + var result = publishedRouter.BuildRequest(request); + + Assert.IsFalse(result.Success()); + } + + [Test] + public async Task ConfigureRequest_Returns_False_When_IsRedirect() + { + var umbracoContextAccessor = GetUmbracoContextAccessor(); + var publishedRouter = CreatePublishedRouter(umbracoContextAccessor); + var request = await publishedRouter.CreateRequestAsync(umbracoContextAccessor.GetRequiredUmbracoContext().CleanedUmbracoUrl); + var content = GetPublishedContentMock(); + request.SetPublishedContent(content.Object); + request.SetCulture("en-AU"); + request.SetRedirect("/hello"); + var result = publishedRouter.BuildRequest(request); + + Assert.IsFalse(result.Success()); + } + + private Mock GetPublishedContentMock() + { + var pc = new Mock(); + pc.Setup(content => content.Id).Returns(1); + pc.Setup(content => content.Name).Returns("test"); + pc.Setup(content => content.CreateDate).Returns(DateTime.Now); + pc.Setup(content => content.UpdateDate).Returns(DateTime.Now); + pc.Setup(content => content.Path).Returns("-1,1"); + pc.Setup(content => content.Parent).Returns(() => null); + pc.Setup(content => content.Properties).Returns(new Collection()); + pc.Setup(content => content.ContentType).Returns(new PublishedContentType(Guid.NewGuid(), 22, "anything", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing)); + return pc; + } + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs new file mode 100644 index 000000000000..59884882bfa1 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Logging; +using NUnit.Framework; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing +{ + [TestFixture] + public class UrlProviderWithHideTopLevelNodeFromPathTests : PublishedSnapshotServiceTestBase + { + [SetUp] + public override void Setup() + { + base.Setup(); + + string xml = PublishedContentXml.BaseWebTestXml(1234); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + + GlobalSettings.HideTopLevelNodeFromPath = true; + } + + [TestCase(1046, "/")] + [TestCase(1173, "/sub1/")] + [TestCase(1174, "/sub1/sub2/")] + [TestCase(1176, "/sub1/sub-3/")] + [TestCase(1177, "/sub1/custom-sub-1/")] + [TestCase(1178, "/sub1/custom-sub-2/")] + [TestCase(1175, "/sub-2/")] + [TestCase(1172, "/test-page/")] // not hidden because not first root + public void Get_Url_Hiding_Top_Level(int nodeId, string niceUrlMatch) + { + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; + + var umbracoContextAccessor = GetUmbracoContextAccessor("/test"); + + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); + + var result = urlProvider.GetUrl(nodeId); + Assert.AreEqual(niceUrlMatch, result); + } + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlProviderWithoutHideTopLevelNodeFromPathTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlProviderWithoutHideTopLevelNodeFromPathTests.cs new file mode 100644 index 000000000000..8c68aa5c36a7 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlProviderWithoutHideTopLevelNodeFromPathTests.cs @@ -0,0 +1,336 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PublishedCache; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; +using Umbraco.Cms.Tests.Common; +using Umbraco.Cms.Tests.Common.Builders; +using Umbraco.Cms.Tests.Common.Builders.Extensions; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing +{ + [TestFixture] + public class UrlProviderWithoutHideTopLevelNodeFromPathTests : PublishedSnapshotServiceTestBase + { + private const string CacheKeyPrefix = "NuCache.ContentCache.RouteByContent"; + + [SetUp] + public override void Setup() + { + base.Setup(); + + + + GlobalSettings.HideTopLevelNodeFromPath = false; + } + + private void PopulateCache(string culture = "fr-FR") + { + var dataTypes = GetDefaultDataTypes(); + var propertyDataTypes = new Dictionary + { + // we only have one data type for this test which will be resolved with string empty. + [string.Empty] = dataTypes[0] + }; + var contentType1 = new ContentType(ShortStringHelper, -1); + + ContentData rootData = new ContentDataBuilder() + .WithName("Page" + Guid.NewGuid()) + .WithCultureInfos(new Dictionary + { + [culture] = new CultureVariation + { + Name = "root", + IsDraft = true, + Date = DateTime.Now, + UrlSegment = "root" + }, + }) + .Build(ShortStringHelper, propertyDataTypes, contentType1, "alias"); + + ContentNodeKit root = ContentNodeKitBuilder.CreateWithContent( + contentType1.Id, + 9876, $"-1,9876", + draftData: rootData, + publishedData: rootData); + + ContentData parentData = new ContentDataBuilder() + .WithName("Page" + Guid.NewGuid()) + .WithCultureInfos(new Dictionary + { + [culture] = new CultureVariation + { + Name = "home", + IsDraft = true, + Date = DateTime.Now, + UrlSegment = "home" + }, + }) + .Build(); + + ContentNodeKit parent = ContentNodeKitBuilder.CreateWithContent( + contentType1.Id, + 5432, $"-1,9876,5432", + parentContentId: 9876, + draftData: parentData, + publishedData: parentData); + + ContentData contentData = new ContentDataBuilder() + .WithName("Page" + Guid.NewGuid()) + .WithCultureInfos(new Dictionary + { + [culture] = new CultureVariation + { + Name = "name-fr2", + IsDraft = true, + Date = DateTime.Now, + UrlSegment = "test-fr" + }, + }) + .Build(); + + ContentNodeKit content = ContentNodeKitBuilder.CreateWithContent( + contentType1.Id, + 1234, $"-1,9876,5432,1234", + parentContentId: 5432, + draftData: contentData, + publishedData: contentData); + + InitializedCache(new[] { root, parent, content }, new[] { contentType1 }, dataTypes: dataTypes); + } + + private void SetDomains1() + { + var domainService = Mock.Get(DomainService); + + domainService.Setup(service => service.GetAll(It.IsAny())) + .Returns((bool incWildcards) => new[] + { + new UmbracoDomain("http://example.us/") {Id = 1, RootContentId = 9876, LanguageIsoCode = "en-US"}, + new UmbracoDomain("http://example.fr/") {Id = 2, RootContentId = 9876, LanguageIsoCode = "fr-FR"} + }); + } + + /// + /// This checks that when we retrieve a NiceUrl for multiple items that there are no issues with cache overlap + /// and that they are all cached correctly. + /// + [Test] + public void Ensure_Cache_Is_Correct() + { + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = false }; + + string xml = PublishedContentXml.BaseWebTestXml(1234); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + + var umbracoContextAccessor = GetUmbracoContextAccessor("/test"); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); + + var samples = new Dictionary { + { 1046, "/home" }, + { 1173, "/home/sub1" }, + { 1174, "/home/sub1/sub2" }, + { 1176, "/home/sub1/sub-3" }, + { 1177, "/home/sub1/custom-sub-1" }, + { 1178, "/home/sub1/custom-sub-2" }, + { 1175, "/home/sub-2" }, + { 1172, "/test-page" } + }; + + foreach (var sample in samples) + { + var result = urlProvider.GetUrl(sample.Key); + Assert.AreEqual(sample.Value, result); + } + + var randomSample = new KeyValuePair(1177, "/home/sub1/custom-sub-1"); + for (int i = 0; i < 5; i++) + { + var result = urlProvider.GetUrl(randomSample.Key); + Assert.AreEqual(randomSample.Value, result); + } + + + var cache = (FastDictionaryAppCache)umbracoContext.PublishedSnapshot.ElementsCache; + var cachedRoutes = cache.Keys.Where(x => x.StartsWith(CacheKeyPrefix)).ToList(); + Assert.AreEqual(8, cachedRoutes.Count); + + foreach (var sample in samples) + { + var cacheKey = $"{CacheKeyPrefix}[P:{sample.Key}]"; + var found = (string)cache.Get(cacheKey); + Assert.IsNotNull(found); + Assert.AreEqual(sample.Value, found); + } + } + + [TestCase(1046, "/home/")] + [TestCase(1173, "/home/sub1/")] + [TestCase(1174, "/home/sub1/sub2/")] + [TestCase(1176, "/home/sub1/sub-3/")] + [TestCase(1177, "/home/sub1/custom-sub-1/")] + [TestCase(1178, "/home/sub1/custom-sub-2/")] + [TestCase(1175, "/home/sub-2/")] + [TestCase(1172, "/test-page/")] + public void Get_Url_Not_Hiding_Top_Level(int nodeId, string niceUrlMatch) + { + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; + + string xml = PublishedContentXml.BaseWebTestXml(1234); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + + var umbracoContextAccessor = GetUmbracoContextAccessor("/test"); + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); + + var result = urlProvider.GetUrl(nodeId); + Assert.AreEqual(niceUrlMatch, result); + } + + [Test] + [TestCase("fr-FR", ExpectedResult = "#")] // Non default cultures cannot return urls + [TestCase("en-US", ExpectedResult = "/root/home/test-fr/")] // Default culture can return urls + public string Get_Url_For_Culture_Variant_Without_Domains_Non_Current_Url(string culture) + { + const string currentUri = "http://example.us/test"; + + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; + + PopulateCache(culture); + + var umbracoContextAccessor = GetUmbracoContextAccessor(currentUri); + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); + + + //even though we are asking for a specific culture URL, there are no domains assigned so all that can be returned is a normal relative URL. + var url = urlProvider.GetUrl(1234, culture: culture); + + return url; + } + + /// + /// This tests DefaultUrlProvider.GetUrl with a specific culture when the current URL is the culture specific domain + /// + [Test] + public void Get_Url_For_Culture_Variant_With_Current_Url() + { + const string currentUri = "http://example.fr/test"; + + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; + + PopulateCache(); + + SetDomains1(); + + var umbracoContextAccessor = GetUmbracoContextAccessor(currentUri); + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); + + var url = urlProvider.GetUrl(1234, culture: "fr-FR"); + + Assert.AreEqual("/home/test-fr/", url); + } + + /// + /// This tests DefaultUrlProvider.GetUrl with a specific culture when the current URL is not the culture specific domain + /// + [Test] + public void Get_Url_For_Culture_Variant_Non_Current_Url() + { + const string currentUri = "http://example.us/test"; + + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; + + PopulateCache(); + + SetDomains1(); + + var umbracoContextAccessor = GetUmbracoContextAccessor(currentUri); + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); + var url = urlProvider.GetUrl(1234, culture: "fr-FR"); + + //the current uri is not the culture specific domain we want, so the result is an absolute path to the culture specific domain + Assert.AreEqual("http://example.fr/home/test-fr/", url); + } + + [Test] + public void Get_Url_Relative_Or_Absolute() + { + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; + + string xml = PublishedContentXml.BaseWebTestXml(1234); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + + var umbracoContextAccessor = GetUmbracoContextAccessor("http://example.com/test"); + + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); + + Assert.AreEqual("/home/sub1/custom-sub-1/", urlProvider.GetUrl(1177)); + + urlProvider.Mode = UrlMode.Absolute; + Assert.AreEqual("http://example.com/home/sub1/custom-sub-1/", urlProvider.GetUrl(1177)); + } + + [Test] + public void Get_Url_Unpublished() + { + var requestHandlerSettings = new RequestHandlerSettings(); + + string xml = PublishedContentXml.BaseWebTestXml(1234); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + + var umbracoContextAccessor = GetUmbracoContextAccessor("http://example.com/test"); + + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); + + //mock the Umbraco settings that we need + + Assert.AreEqual("#", urlProvider.GetUrl(999999)); + + urlProvider.Mode = UrlMode.Absolute; + + Assert.AreEqual("#", urlProvider.GetUrl(999999)); + } + } +} diff --git a/tests/Umbraco.Tests/Routing/ContentFinderByAliasTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlRoutingTestBase.cs similarity index 81% rename from tests/Umbraco.Tests/Routing/ContentFinderByAliasTests.cs rename to tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlRoutingTestBase.cs index 82dea51d1c1c..65eea64f75c4 100644 --- a/tests/Umbraco.Tests/Routing/ContentFinderByAliasTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlRoutingTestBase.cs @@ -1,68 +1,55 @@ -using System; +using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.Routing; -using Constants = Umbraco.Cms.Core.Constants; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; -namespace Umbraco.Tests.Routing +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing { - // TODO: We should be able to decouple this from the base db tests since we're just mocking the services now - [TestFixture] - public class ContentFinderByAliasTests : UrlRoutingTestBase + public abstract class UrlRoutingTestBase : PublishedSnapshotServiceTestBase { - private PublishedContentType _publishedContentType; - - protected override void Initialize() + [SetUp] + public override void Setup() { - base.Initialize(); + base.Setup(); - var properties = new[] - { - new PublishedPropertyType("umbracoUrlAlias", Constants.DataTypes.Textbox, false, ContentVariation.Nothing, - new PropertyValueConverterCollection(Enumerable.Empty()), - Mock.Of(), - Mock.Of()), - }; - _publishedContentType = new PublishedContentType(Guid.NewGuid(), 0, "Doc", PublishedItemType.Content, Enumerable.Empty(), properties, ContentVariation.Nothing); - } + string xml = GetXmlContent(1234); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); - protected override PublishedContentType GetPublishedContentTypeByAlias(string alias) - { - if (alias == "Doc") return _publishedContentType; - return null; } - [TestCase("/this/is/my/alias", 1001)] - [TestCase("/anotheralias", 1001)] - [TestCase("/page2/alias", 10011)] - [TestCase("/2ndpagealias", 10011)] - [TestCase("/only/one/alias", 100111)] - [TestCase("/ONLY/one/Alias", 100111)] - [TestCase("/alias43", 100121)] - public async Task Lookup_By_Url_Alias(string urlAsString, int nodeMatch) + // Sets up the mock domain service + protected override ServiceContext CreateServiceContext(IContentType[] contentTypes, IMediaType[] mediaTypes, IDataType[] dataTypes) { - var umbracoContext = GetUmbracoContext(urlAsString); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext)); - var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); - var lookup = - new ContentFinderByUrlAlias(LoggerFactory.CreateLogger(), Mock.Of(), VariationContextAccessor, GetUmbracoContextAccessor(umbracoContext)); + var serviceContext = base.CreateServiceContext(contentTypes, mediaTypes, dataTypes); - var result = lookup.TryFindContent(frequest); + //setup mock domain service + var domainService = Mock.Get(serviceContext.DomainService); + domainService.Setup(service => service.GetAll(It.IsAny())) + .Returns((bool incWildcards) => new[] + { + new UmbracoDomain("domain1.com/"){Id = 1, LanguageId = LangDeId, RootContentId = 1001, LanguageIsoCode = "de-DE"}, + new UmbracoDomain("domain1.com/en"){Id = 2, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}, + new UmbracoDomain("domain1.com/fr"){Id = 3, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"} + }); - Assert.IsTrue(result); - Assert.AreEqual(frequest.PublishedContent.Id, nodeMatch); + return serviceContext; } - protected override string GetXmlContent(int templateId) - { - return @" + protected virtual string GetXmlContent(int templateId) + => @" @@ -147,7 +134,12 @@ protected override string GetXmlContent(int templateId) "; - } + public const int LangDeId = 333; + public const int LangEngId = 334; + public const int LangFrId = 335; + public const int LangCzId = 336; + public const int LangNlId = 337; + public const int LangDkId = 338; } } diff --git a/tests/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlsProviderWithDomainsTests.cs similarity index 56% rename from tests/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs rename to tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlsProviderWithDomainsTests.cs index 4f9fdef8e0bd..28c8dd719467 100644 --- a/tests/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlsProviderWithDomainsTests.cs @@ -1,10 +1,11 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; +using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.PublishedContent; @@ -13,77 +14,83 @@ using Umbraco.Cms.Core.Web; using Umbraco.Cms.Tests.Common; using Umbraco.Extensions; -using Umbraco.Tests.LegacyXmlPublishedCache; -namespace Umbraco.Tests.Routing +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing { [TestFixture] public class UrlsProviderWithDomainsTests : UrlRoutingTestBase { - private IUmbracoContextAccessor UmbracoContextAccessor { get; } = new TestUmbracoContextAccessor(); - protected override void Compose() + private const string CacheKeyPrefix = "NuCache.ContentCache.RouteByContent"; + + private void SetDomains1() { - base.Compose(); + var domainService = Mock.Get(DomainService); - Builder.Services.AddUnique(Mock.Of()); - Builder.Services.AddTransient(); + domainService.Setup(service => service.GetAll(It.IsAny())) + .Returns((bool incWildcards) => new[] + { + new UmbracoDomain("domain1.com") {Id = 1, LanguageId = LangFrId, RootContentId = 1001, LanguageIsoCode = "fr-FR"} + }); } - void SetDomains1() + private void SetDomains2() { - SetupDomainServiceMock(new[] - { - new UmbracoDomain("domain1.com") {Id = 1, LanguageId = LangFrId, RootContentId = 1001, LanguageIsoCode = "fr-FR"} - }); - } + var domainService = Mock.Get(DomainService); - void SetDomains2() - { - SetupDomainServiceMock(new[] - { - new UmbracoDomain("http://domain1.com/foo") {Id = 1, LanguageId = LangFrId, RootContentId = 1001, LanguageIsoCode = "fr-FR"} - }); + domainService.Setup(service => service.GetAll(It.IsAny())) + .Returns((bool incWildcards) => new[] + { + new UmbracoDomain("http://domain1.com/foo") {Id = 1, LanguageId = LangFrId, RootContentId = 1001, LanguageIsoCode = "fr-FR"} + }); } - void SetDomains3() + private void SetDomains3() { - SetupDomainServiceMock(new[] - { - new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangFrId, RootContentId = 10011, LanguageIsoCode = "fr-FR"} - }); + var domainService = Mock.Get(DomainService); + + domainService.Setup(service => service.GetAll(It.IsAny())) + .Returns((bool incWildcards) => new[] + { + new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangFrId, RootContentId = 10011, LanguageIsoCode = "fr-FR"} + }); } - void SetDomains4() + private void SetDomains4() { - SetupDomainServiceMock(new[] - { - new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"}, - new UmbracoDomain("http://domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}, - new UmbracoDomain("http://domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"}, - new UmbracoDomain("http://domain3.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1003, LanguageIsoCode = "en-US"}, - new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"}, - new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"} - }); + var domainService = Mock.Get(DomainService); + + domainService.Setup(service => service.GetAll(It.IsAny())) + .Returns((bool incWildcards) => new[] + { + new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"}, + new UmbracoDomain("http://domain1.com/en") {Id = 2, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}, + new UmbracoDomain("http://domain1.com/fr") {Id = 3, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"}, + new UmbracoDomain("http://domain3.com/") {Id = 4, LanguageId = LangEngId, RootContentId = 1003, LanguageIsoCode = "en-US"}, + new UmbracoDomain("http://domain3.com/en") {Id = 5, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"}, + new UmbracoDomain("http://domain3.com/fr") {Id = 6, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"} + }); } - void SetDomains5() + private void SetDomains5() { - SetupDomainServiceMock(new[] - { - new UmbracoDomain("http://domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}, - new UmbracoDomain("http://domain1a.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}, - new UmbracoDomain("http://domain1b.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}, - new UmbracoDomain("http://domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"}, - new UmbracoDomain("http://domain1a.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"}, - new UmbracoDomain("http://domain1b.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"}, - new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"}, - new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"} - }); + var domainService = Mock.Get(DomainService); + + domainService.Setup(service => service.GetAll(It.IsAny())) + .Returns((bool incWildcards) => new[] + { + new UmbracoDomain("http://domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}, + new UmbracoDomain("http://domain1a.com/en") {Id = 2, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}, + new UmbracoDomain("http://domain1b.com/en") {Id = 3, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}, + new UmbracoDomain("http://domain1.com/fr") {Id = 4, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"}, + new UmbracoDomain("http://domain1a.com/fr") {Id = 5, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"}, + new UmbracoDomain("http://domain1b.com/fr") {Id = 6, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"}, + new UmbracoDomain("http://domain3.com/en") {Id = 7, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"}, + new UmbracoDomain("http://domain3.com/fr") {Id = 8, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"} + }); } protected override string GetXmlContent(int templateId) - { - return @" + => @" @@ -162,7 +169,6 @@ protected override string GetXmlContent(int templateId) "; - } // with one simple domain "domain1.com" // basic tests @@ -179,21 +185,18 @@ protected override string GetXmlContent(int templateId) [TestCase(10011, "https://domain1.com", false, "/1001-1/")] public void Get_Url_SimpleDomain(int nodeId, string currentUrl, bool absolute, string expected) { + SetDomains1(); + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; + GlobalSettings.HideTopLevelNodeFromPath = false; - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); + var umbracoContextAccessor = GetUmbracoContextAccessor("/test"); - SetDomains1(); + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); var currentUri = new Uri(currentUrl); var mode = absolute ? UrlMode.Absolute : UrlMode.Auto; - var result = publishedUrlProvider.GetUrl(nodeId, mode, current: currentUri); + var result = urlProvider.GetUrl(nodeId, mode, current: currentUri); Assert.AreEqual(expected, result); } @@ -212,21 +215,18 @@ public void Get_Url_SimpleDomain(int nodeId, string currentUrl, bool absolute, s [TestCase(10011, "https://domain1.com", false, "http://domain1.com/foo/1001-1/")] public void Get_Url_SimpleWithSchemeAndPath(int nodeId, string currentUrl, bool absolute, string expected) { + SetDomains2(); + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; + GlobalSettings.HideTopLevelNodeFromPath = false; - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); + var umbracoContextAccessor = GetUmbracoContextAccessor("/test"); - SetDomains2(); + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); var currentUri = new Uri(currentUrl); var mode = absolute ? UrlMode.Absolute : UrlMode.Auto; - var result = publishedUrlProvider.GetUrl(nodeId, mode, current : currentUri); + var result = urlProvider.GetUrl(nodeId, mode, current: currentUri); Assert.AreEqual(expected, result); } @@ -237,21 +237,18 @@ public void Get_Url_SimpleWithSchemeAndPath(int nodeId, string currentUrl, bool [TestCase(1002, "http://domain1.com", false, "/1002/")] public void Get_Url_DeepDomain(int nodeId, string currentUrl, bool absolute, string expected) { + SetDomains3(); + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; + GlobalSettings.HideTopLevelNodeFromPath = false; - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); + var umbracoContextAccessor = GetUmbracoContextAccessor("/test"); - SetDomains3(); + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); var currentUri = new Uri(currentUrl); var mode = absolute ? UrlMode.Absolute : UrlMode.Auto; - var result = publishedUrlProvider.GetUrl(nodeId, mode, current : currentUri); + var result = urlProvider.GetUrl(nodeId, mode, current: currentUri); Assert.AreEqual(expected, result); } @@ -268,152 +265,130 @@ public void Get_Url_DeepDomain(int nodeId, string currentUrl, bool absolute, str [TestCase(100321, "http://domain3.com", false, "/fr/1003-2-1/")] public void Get_Url_NestedDomains(int nodeId, string currentUrl, bool absolute, string expected) { + SetDomains4(); + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; + GlobalSettings.HideTopLevelNodeFromPath = false; - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider( - Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); + var umbracoContextAccessor = GetUmbracoContextAccessor("/test"); + + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); - SetDomains4(); var currentUri = new Uri(currentUrl); var mode = absolute ? UrlMode.Absolute : UrlMode.Auto; - var result = publishedUrlProvider.GetUrl(nodeId, mode, current : currentUri); + var result = urlProvider.GetUrl(nodeId, mode, current: currentUri); Assert.AreEqual(expected, result); } [Test] public void Get_Url_DomainsAndCache() { + SetDomains4(); + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; + GlobalSettings.HideTopLevelNodeFromPath = false; + + var umbracoContextAccessor = GetUmbracoContextAccessor("/test"); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider( - Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); - SetDomains4(); string ignore; - ignore = publishedUrlProvider.GetUrl(1001, UrlMode.Auto, current: new Uri("http://domain1.com")); - ignore = publishedUrlProvider.GetUrl(10011, UrlMode.Auto, current: new Uri("http://domain1.com")); - ignore = publishedUrlProvider.GetUrl(100111, UrlMode.Auto, current: new Uri("http://domain1.com")); - ignore = publishedUrlProvider.GetUrl(10012, UrlMode.Auto, current: new Uri("http://domain1.com")); - ignore = publishedUrlProvider.GetUrl(100121, UrlMode.Auto, current: new Uri("http://domain1.com")); - ignore = publishedUrlProvider.GetUrl(10013, UrlMode.Auto, current: new Uri("http://domain1.com")); - ignore = publishedUrlProvider.GetUrl(1002, UrlMode.Auto, current: new Uri("http://domain1.com")); - ignore = publishedUrlProvider.GetUrl(1001, UrlMode.Auto, current: new Uri("http://domain2.com")); - ignore = publishedUrlProvider.GetUrl(10011, UrlMode.Auto, current: new Uri("http://domain2.com")); - ignore = publishedUrlProvider.GetUrl(100111, UrlMode.Auto, current: new Uri("http://domain2.com")); - ignore = publishedUrlProvider.GetUrl(1002, UrlMode.Auto, current: new Uri("http://domain2.com")); - - var cache = umbracoContext.Content as PublishedContentCache; - if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); - var cachedRoutes = cache.RoutesCache.GetCachedRoutes(); + ignore = urlProvider.GetUrl(1001, UrlMode.Auto, current: new Uri("http://domain1.com")); + ignore = urlProvider.GetUrl(10011, UrlMode.Auto, current: new Uri("http://domain1.com")); + ignore = urlProvider.GetUrl(100111, UrlMode.Auto, current: new Uri("http://domain1.com")); + ignore = urlProvider.GetUrl(10012, UrlMode.Auto, current: new Uri("http://domain1.com")); + ignore = urlProvider.GetUrl(100121, UrlMode.Auto, current: new Uri("http://domain1.com")); + ignore = urlProvider.GetUrl(10013, UrlMode.Auto, current: new Uri("http://domain1.com")); + ignore = urlProvider.GetUrl(1002, UrlMode.Auto, current: new Uri("http://domain1.com")); + ignore = urlProvider.GetUrl(1001, UrlMode.Auto, current: new Uri("http://domain2.com")); + ignore = urlProvider.GetUrl(10011, UrlMode.Auto, current: new Uri("http://domain2.com")); + ignore = urlProvider.GetUrl(100111, UrlMode.Auto, current: new Uri("http://domain2.com")); + ignore = urlProvider.GetUrl(1002, UrlMode.Auto, current: new Uri("http://domain2.com")); + + + var cache = (FastDictionaryAppCache)umbracoContext.PublishedSnapshot.ElementsCache; + var cachedRoutes = cache.Keys.Where(x => x.StartsWith(CacheKeyPrefix)).ToList(); Assert.AreEqual(7, cachedRoutes.Count); - var cachedIds = cache.RoutesCache.GetCachedIds(); - Assert.AreEqual(0, cachedIds.Count); + //var cachedIds = cache.RoutesCache.GetCachedIds(); + //Assert.AreEqual(0, cachedIds.Count); - CheckRoute(cachedRoutes, cachedIds, 1001, "1001/"); - CheckRoute(cachedRoutes, cachedIds, 10011, "10011/"); - CheckRoute(cachedRoutes, cachedIds, 100111, "10011/1001-1-1"); - CheckRoute(cachedRoutes, cachedIds, 10012, "10012/"); - CheckRoute(cachedRoutes, cachedIds, 100121, "10012/1001-2-1"); - CheckRoute(cachedRoutes, cachedIds, 10013, "1001/1001-3"); - CheckRoute(cachedRoutes, cachedIds, 1002, "/1002"); + CheckRoute(cache, 1001, "1001/"); + CheckRoute(cache, 10011, "10011/"); + CheckRoute(cache, 100111, "10011/1001-1-1"); + CheckRoute(cache, 10012, "10012/"); + CheckRoute(cache, 100121, "10012/1001-2-1"); + CheckRoute(cache, 10013, "1001/1001-3"); + CheckRoute(cache, 1002, "/1002"); // use the cache - Assert.AreEqual("/", publishedUrlProvider.GetUrl(1001, UrlMode.Auto, current: new Uri("http://domain1.com"))); - Assert.AreEqual("/en/", publishedUrlProvider.GetUrl(10011, UrlMode.Auto, current: new Uri("http://domain1.com"))); - Assert.AreEqual("/en/1001-1-1/", publishedUrlProvider.GetUrl(100111, UrlMode.Auto, current: new Uri("http://domain1.com"))); - Assert.AreEqual("/fr/", publishedUrlProvider.GetUrl(10012, UrlMode.Auto, current: new Uri("http://domain1.com"))); - Assert.AreEqual("/fr/1001-2-1/", publishedUrlProvider.GetUrl(100121, UrlMode.Auto, current: new Uri("http://domain1.com"))); - Assert.AreEqual("/1001-3/", publishedUrlProvider.GetUrl(10013, UrlMode.Auto, current: new Uri("http://domain1.com"))); - Assert.AreEqual("/1002/", publishedUrlProvider.GetUrl(1002, UrlMode.Auto, current: new Uri("http://domain1.com"))); - - Assert.AreEqual("http://domain1.com/fr/1001-2-1/", publishedUrlProvider.GetUrl(100121, UrlMode.Auto, current: new Uri("http://domain2.com"))); + Assert.AreEqual("/", urlProvider.GetUrl(1001, UrlMode.Auto, current: new Uri("http://domain1.com"))); + Assert.AreEqual("/en/", urlProvider.GetUrl(10011, UrlMode.Auto, current: new Uri("http://domain1.com"))); + Assert.AreEqual("/en/1001-1-1/", urlProvider.GetUrl(100111, UrlMode.Auto, current: new Uri("http://domain1.com"))); + Assert.AreEqual("/fr/", urlProvider.GetUrl(10012, UrlMode.Auto, current: new Uri("http://domain1.com"))); + Assert.AreEqual("/fr/1001-2-1/", urlProvider.GetUrl(100121, UrlMode.Auto, current: new Uri("http://domain1.com"))); + Assert.AreEqual("/1001-3/", urlProvider.GetUrl(10013, UrlMode.Auto, current: new Uri("http://domain1.com"))); + Assert.AreEqual("/1002/", urlProvider.GetUrl(1002, UrlMode.Auto, current: new Uri("http://domain1.com"))); + + Assert.AreEqual("http://domain1.com/fr/1001-2-1/", urlProvider.GetUrl(100121, UrlMode.Auto, current: new Uri("http://domain2.com"))); } - private static void CheckRoute(IDictionary routes, IDictionary ids, int id, string route) + private static void CheckRoute(FastDictionaryAppCache routes, int id, string route) { - Assert.IsTrue(routes.ContainsKey(id)); - Assert.AreEqual(route, routes[id]); - Assert.IsFalse(ids.ContainsKey(route)); + var cacheKey = $"{CacheKeyPrefix}[P:{id}]"; + var found = (string)routes.Get(cacheKey); + Assert.IsNotNull(found); + Assert.AreEqual(route, found); } [Test] public void Get_Url_Relative_Or_Absolute() { + SetDomains4(); + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; + GlobalSettings.HideTopLevelNodeFromPath = false; - var umbracoContext = GetUmbracoContext("http://domain1.com/test", 1111, globalSettings: globalSettings); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider( - Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); + var umbracoContextAccessor = GetUmbracoContextAccessor("http://domain1.com/test"); + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); - SetDomains4(); - Assert.AreEqual("/en/1001-1-1/", publishedUrlProvider.GetUrl(100111)); - Assert.AreEqual("http://domain3.com/en/1003-1-1/", publishedUrlProvider.GetUrl(100311)); + Assert.AreEqual("/en/1001-1-1/", urlProvider.GetUrl(100111)); + Assert.AreEqual("http://domain3.com/en/1003-1-1/", urlProvider.GetUrl(100311)); - publishedUrlProvider.Mode = UrlMode.Absolute; + urlProvider.Mode = UrlMode.Absolute; - Assert.AreEqual("http://domain1.com/en/1001-1-1/", publishedUrlProvider.GetUrl(100111)); - Assert.AreEqual("http://domain3.com/en/1003-1-1/", publishedUrlProvider.GetUrl(100311)); + Assert.AreEqual("http://domain1.com/en/1001-1-1/", urlProvider.GetUrl(100111)); + Assert.AreEqual("http://domain3.com/en/1003-1-1/", urlProvider.GetUrl(100311)); } [Test] public void Get_Url_Alternate() { + SetDomains5(); + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; + GlobalSettings.HideTopLevelNodeFromPath = false; - var umbracoContext = GetUmbracoContext("http://domain1.com/en/test", 1111, globalSettings: globalSettings); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider( - Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); + var umbracoContextAccessor = GetUmbracoContextAccessor("http://domain1.com/en/test"); + UrlProvider urlProvider = GetUrlProvider(umbracoContextAccessor, requestHandlerSettings, new WebRoutingSettings(), out UriUtility uriUtility); - SetDomains5(); - var url = publishedUrlProvider.GetUrl(100111, UrlMode.Absolute); + var url = urlProvider.GetUrl(100111, UrlMode.Absolute); Assert.AreEqual("http://domain1.com/en/1001-1-1/", url); - var result = publishedUrlProvider.GetOtherUrls(100111).ToArray(); + var result = urlProvider.GetOtherUrls(100111).ToArray(); - foreach (var x in result) Console.WriteLine(x); + foreach (var x in result) + Console.WriteLine(x); Assert.AreEqual(2, result.Length); Assert.AreEqual(result[0].Text, "http://domain1b.com/en/1001-1-1/"); Assert.AreEqual(result[1].Text, "http://domain1a.com/en/1001-1-1/"); } - private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext, DefaultUrlProvider urlProvider) - { - var webRoutingSettings = new WebRoutingSettings(); - return new UrlProvider( - new TestUmbracoContextAccessor(umbracoContext), - Microsoft.Extensions.Options.Options.Create(webRoutingSettings), - new UrlProviderCollection(new []{urlProvider}), - new MediaUrlProviderCollection(Enumerable.Empty()), - Mock.Of() - ); - } } } diff --git a/tests/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlsWithNestedDomains.cs similarity index 85% rename from tests/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs rename to tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlsWithNestedDomains.cs index ab9058bc9cc7..5e4d7f104e15 100644 --- a/tests/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UrlsWithNestedDomains.cs @@ -5,17 +5,19 @@ using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; +using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Tests.Common; using Umbraco.Extensions; -using Umbraco.Tests.LegacyXmlPublishedCache; -namespace Umbraco.Tests.Routing +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Routing { [TestFixture] public class UrlsWithNestedDomains : UrlRoutingTestBase @@ -25,61 +27,60 @@ public class UrlsWithNestedDomains : UrlRoutingTestBase // using the closest domain to the node - here we test that if we request // a non-canonical route, it is not cached / the cache is not polluted - protected override void Compose() - { - base.Compose(); - Builder.Services.AddUnique(Mock.Of()); - Builder.Services.AddTransient(); - } - [Test] public async Task DoNotPolluteCache() { var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; + GlobalSettings.HideTopLevelNodeFromPath = false; SetDomains1(); const string url = "http://domain1.com/1001-1/1001-1-1"; // get the nice URL for 100111 - var umbracoContext = GetUmbracoContext(url, 9999, globalSettings: globalSettings); - var umbracoContextAccessor = GetUmbracoContextAccessor(umbracoContext); + var umbracoContextAccessor = GetUmbracoContextAccessor(url); + var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); + var urlProvider = new DefaultUrlProvider( Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); + Mock.Of>(), + new SiteDomainMapper(), + umbracoContextAccessor, + new UriUtility(Mock.Of()), + Mock.Of()); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); - Assert.AreEqual("http://domain2.com/1001-1-1/", publishedUrlProvider.GetUrl(100111, UrlMode.Absolute)); + string absUrl = publishedUrlProvider.GetUrl(100111, UrlMode.Absolute); + Assert.AreEqual("http://domain2.com/1001-1-1/", absUrl); + + const string cacheKeyPrefix = "NuCache.ContentCache.RouteByContent"; // check that the proper route has been cached - var cache = umbracoContext.Content as PublishedContentCache; - if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); - var cachedRoutes = cache.RoutesCache.GetCachedRoutes(); - Assert.AreEqual("10011/1001-1-1", cachedRoutes[100111]); + var cache = (FastDictionaryAppCache)umbracoContext.PublishedSnapshot.ElementsCache; + + var cachedRoutes = cache.Keys.Where(x => x.StartsWith(cacheKeyPrefix)).ToList(); + var cacheKey = $"{cacheKeyPrefix}[P:100111]"; + Assert.AreEqual("10011/1001-1-1", cache.Get(cacheKey)); // route a rogue URL var publishedRouter = CreatePublishedRouter(umbracoContextAccessor); - var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); + var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); publishedRouter.FindDomain(frequest); Assert.IsTrue(frequest.HasDomain()); // check that it's been routed - var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger(), GetUmbracoContextAccessor(umbracoContext)); + var lookup = new ContentFinderByUrl(Mock.Of>(), umbracoContextAccessor); var result = lookup.TryFindContent(frequest); Assert.IsTrue(result); Assert.AreEqual(100111, frequest.PublishedContent.Id); // has the cache been polluted? - cachedRoutes = cache.RoutesCache.GetCachedRoutes(); - Assert.AreEqual("10011/1001-1-1", cachedRoutes[100111]); // no - //Assert.AreEqual("1001/1001-1/1001-1-1", cachedRoutes[100111]); // yes + cachedRoutes = cache.Keys.Where(x => x.StartsWith(cacheKeyPrefix)).ToList(); + Assert.AreEqual("10011/1001-1-1", cache.Get(cacheKey)); // no // what's the nice URL now? Assert.AreEqual("http://domain2.com/1001-1-1/", publishedUrlProvider.GetUrl(100111)); // good - //Assert.AreEqual("http://domain1.com/1001-1/1001-1-1", routingContext.NiceUrlProvider.GetNiceUrl(100111, true)); // bad } private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext, object urlProvider) @@ -87,14 +88,16 @@ private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoCon throw new NotImplementedException(); } - void SetDomains1() + private void SetDomains1() { - SetupDomainServiceMock(new[] - { - new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"}, - new UmbracoDomain("http://domain2.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"} - }); - + var domainService = Mock.Get(DomainService); + + domainService.Setup(service => service.GetAll(It.IsAny())) + .Returns((bool incWildcards) => new[] + { + new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"}, + new UmbracoDomain("http://domain2.com/") {Id = 2, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"} + }); } private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext, DefaultUrlProvider urlProvider) @@ -103,15 +106,14 @@ private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoCon return new UrlProvider( new TestUmbracoContextAccessor(umbracoContext), Microsoft.Extensions.Options.Options.Create(webRoutingSettings), - new UrlProviderCollection(new []{urlProvider}), - new MediaUrlProviderCollection(Enumerable.Empty()), + new UrlProviderCollection(() => new[] { urlProvider }), + new MediaUrlProviderCollection(() => Enumerable.Empty()), Mock.Of() ); } protected override string GetXmlContent(int templateId) - { - return @" + => @" @@ -190,6 +192,5 @@ protected override string GetXmlContent(int templateId) "; - } } } diff --git a/tests/Umbraco.Tests/PublishedContent/ContentSerializationTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/ContentSerializationTests.cs similarity index 84% rename from tests/Umbraco.Tests/PublishedContent/ContentSerializationTests.cs rename to tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/ContentSerializationTests.cs index 9a44cf35f960..46824d6386ff 100644 --- a/tests/Umbraco.Tests/PublishedContent/ContentSerializationTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/ContentSerializationTests.cs @@ -1,12 +1,12 @@ -using Moq; +using Moq; using NUnit.Framework; using System; using System.Collections.Generic; -using Umbraco.Core.Models; -using Umbraco.Core.PropertyEditors; -using Umbraco.Web.PublishedCache.NuCache.DataSource; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; -namespace Umbraco.Tests.PublishedContent +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache { [TestFixture] public class ContentSerializationTests @@ -77,9 +77,12 @@ public class CultureVariationComparer : Comparer { public override int Compare(CultureVariation x, CultureVariation y) { - if (x == null && y == null) return 0; - if (x == null && y != null) return -1; - if (x != null && y == null) return 1; + if (x == null && y == null) + return 0; + if (x == null && y != null) + return -1; + if (x != null && y == null) + return 1; return x.Date.CompareTo(y.Date) | x.IsDraft.CompareTo(y.IsDraft) | x.Name.CompareTo(y.Name) | x.UrlSegment.CompareTo(y.UrlSegment); } @@ -89,9 +92,12 @@ public class PropertyDataComparer : Comparer { public override int Compare(PropertyData x, PropertyData y) { - if (x == null && y == null) return 0; - if (x == null && y != null) return -1; - if (x != null && y == null) return 1; + if (x == null && y == null) + return 0; + if (x == null && y != null) + return -1; + if (x != null && y == null) + return 1; var xVal = x.Value?.ToString() ?? string.Empty; var yVal = y.Value?.ToString() ?? string.Empty; diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentCacheTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentCacheTests.cs new file mode 100644 index 000000000000..0ef8a856fdf2 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentCacheTests.cs @@ -0,0 +1,85 @@ +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.PublishedCache; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache +{ + [TestFixture] + public class PublishContentCacheTests : PublishedSnapshotServiceTestBase + { + private IPublishedContentCache _cache; + + [SetUp] + public override void Setup() + { + base.Setup(); + + string xml = PublishedContentXml.PublishContentCacheTestsXml(); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + // configure the Home content type to be composed of another for tests. + var compositionType = new ContentType(TestHelper.ShortStringHelper, -1) + { + Alias = "MyCompositionAlias" + }; + contentTypes.First(x => x.Alias == "Home").AddContentType(compositionType); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + + _cache = GetPublishedSnapshot().Content; + } + + [Test] + public void Has_Content() + { + Assert.IsTrue(_cache.HasContent()); + } + + + [Test] + public void Get_Root_Docs() + { + var result = _cache.GetAtRoot(); + Assert.AreEqual(2, result.Count()); + Assert.AreEqual(1046, result.ElementAt(0).Id); + Assert.AreEqual(1172, result.ElementAt(1).Id); + } + + + [TestCase("/", 1046)] + [TestCase("/home", 1046)] + [TestCase("/Home", 1046)] //test different cases + [TestCase("/home/sub1", 1173)] + [TestCase("/Home/sub1", 1173)] + [TestCase("/home/Sub1", 1173)] //test different cases + [TestCase("/home/Sub'Apostrophe", 1177)] + public void Get_Node_By_Route(string route, int nodeId) + { + var result = _cache.GetByRoute(route, false); + Assert.IsNotNull(result); + Assert.AreEqual(nodeId, result.Id); + } + + + + [TestCase("/", 1046)] + [TestCase("/sub1", 1173)] + [TestCase("/Sub1", 1173)] + public void Get_Node_By_Route_Hiding_Top_Level_Nodes(string route, int nodeId) + { + var result = _cache.GetByRoute(route, true); + Assert.IsNotNull(result); + Assert.AreEqual(nodeId, result.Id); + } + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentDataTableTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentDataTableTests.cs new file mode 100644 index 000000000000..80920e071fdc --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentDataTableTests.cs @@ -0,0 +1,200 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; +using Umbraco.Cms.Tests.Common.Builders; +using Umbraco.Cms.Tests.Common.Builders.Extensions; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache +{ + /// + /// Unit tests for IPublishedContent and extensions + /// + [TestFixture] + public class PublishedContentDataTableTests : PublishedSnapshotServiceTestBase + { + private readonly DataType[] _dataTypes = GetDefaultDataTypes(); + + private static ContentType CreateContentType(string name, IDataType dataType, IReadOnlyDictionary propertyAliasesAndNames) + { + var contentType = new ContentType(TestHelper.ShortStringHelper, -1) + { + Alias = name, + Name = name, + Key = Guid.NewGuid(), + Id = name.GetHashCode() + }; + foreach(var prop in propertyAliasesAndNames) + { + contentType.AddPropertyType(new PropertyType(TestHelper.ShortStringHelper, dataType, prop.Key) + { + Name = prop.Value + }); + } + + return contentType; + } + + private IEnumerable CreateCache( + bool createChildren, + IDataType dataType, + out ContentType[] contentTypes) + { + var result = new List(); + var valueCounter = 1; + var parentId = 3; + + var properties = new Dictionary + { + ["property1"] = "Property 1", + ["property2"] = "Property 2", + }; + + ContentType parentContentType = CreateContentType("Parent", dataType, new Dictionary(properties) + { + ["property3"] = "Property 3" + }); + ContentType childContentType = CreateContentType("Child", dataType, new Dictionary(properties) + { + ["property4"] = "Property 4" + }); + ContentType child2ContentType = CreateContentType("Child2", dataType, new Dictionary(properties) + { + ["property4"] = "Property 4" + }); + + contentTypes = new[] { parentContentType, childContentType, child2ContentType }; + + ContentData parentData = new ContentDataBuilder() + .WithName("Page" + Guid.NewGuid()) + .WithProperties(new PropertyDataBuilder() + .WithPropertyData("property1", "value" + valueCounter) + .WithPropertyData("property2", "value" + (valueCounter + 1)) + .WithPropertyData("property3", "value" + (valueCounter + 2)) + .Build()) + .Build(); + + ContentNodeKit parent = ContentNodeKitBuilder.CreateWithContent( + parentContentType.Id, + parentId, $"-1,{parentId}", + draftData: parentData, + publishedData: parentData); + + result.Add(parent); + + if (createChildren) + { + for (int i = 0; i < 3; i++) + { + valueCounter += 3; + var childId = parentId + i + 1; + + ContentData childData = new ContentDataBuilder() + .WithName("Page" + Guid.NewGuid()) + .WithProperties(new PropertyDataBuilder() + .WithPropertyData("property1", "value" + valueCounter) + .WithPropertyData("property2", "value" + (valueCounter + 1)) + .WithPropertyData("property4", "value" + (valueCounter + 2)) + .Build()) + .Build(); + + ContentNodeKit child = ContentNodeKitBuilder.CreateWithContent( + i > 0 ? childContentType.Id : child2ContentType.Id, + childId, $"-1,{parentId},{childId}", i, + draftData: childData, + publishedData: childData); + + result.Add(child); + } + } + + return result; + } + + [Test] + public void To_DataTable() + { + var cache = CreateCache(true, _dataTypes[0], out ContentType[] contentTypes); + InitializedCache(cache, contentTypes, dataTypes: _dataTypes); + + var snapshot = GetPublishedSnapshot(); + var root = snapshot.Content.GetAtRoot().First(); + + var dt = root.ChildrenAsTable( + VariationContextAccessor, + ContentTypeService, + MediaTypeService, + Mock.Of(), + Mock.Of()); + + Assert.AreEqual(11, dt.Columns.Count); + Assert.AreEqual(3, dt.Rows.Count); + Assert.AreEqual("value4", dt.Rows[0]["Property 1"]); + Assert.AreEqual("value5", dt.Rows[0]["Property 2"]); + Assert.AreEqual("value6", dt.Rows[0]["Property 4"]); + Assert.AreEqual("value7", dt.Rows[1]["Property 1"]); + Assert.AreEqual("value8", dt.Rows[1]["Property 2"]); + Assert.AreEqual("value9", dt.Rows[1]["Property 4"]); + Assert.AreEqual("value10", dt.Rows[2]["Property 1"]); + Assert.AreEqual("value11", dt.Rows[2]["Property 2"]); + Assert.AreEqual("value12", dt.Rows[2]["Property 4"]); + } + + [Test] + public void To_DataTable_With_Filter() + { + var cache = CreateCache(true, _dataTypes[0], out ContentType[] contentTypes); + InitializedCache(cache, contentTypes, dataTypes: _dataTypes); + + var snapshot = GetPublishedSnapshot(); + var root = snapshot.Content.GetAtRoot().First(); + + var dt = root.ChildrenAsTable( + VariationContextAccessor, + ContentTypeService, + MediaTypeService, + Mock.Of(), + Mock.Of(), + "Child"); + + Assert.AreEqual(11, dt.Columns.Count); + Assert.AreEqual(2, dt.Rows.Count); + Assert.AreEqual("value7", dt.Rows[0]["Property 1"]); + Assert.AreEqual("value8", dt.Rows[0]["Property 2"]); + Assert.AreEqual("value9", dt.Rows[0]["Property 4"]); + Assert.AreEqual("value10", dt.Rows[1]["Property 1"]); + Assert.AreEqual("value11", dt.Rows[1]["Property 2"]); + Assert.AreEqual("value12", dt.Rows[1]["Property 4"]); + } + + [Test] + public void To_DataTable_No_Rows() + { + var cache = CreateCache(false, _dataTypes[0], out ContentType[] contentTypes); + InitializedCache(cache, contentTypes, dataTypes: _dataTypes); + + var snapshot = GetPublishedSnapshot(); + var root = snapshot.Content.GetAtRoot().First(); + + var dt = root.ChildrenAsTable( + VariationContextAccessor, + ContentTypeService, + MediaTypeService, + Mock.Of(), + Mock.Of()); + + //will return an empty data table + Assert.AreEqual(0, dt.Columns.Count); + Assert.AreEqual(0, dt.Rows.Count); + } + + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentExtensionTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentExtensionTests.cs new file mode 100644 index 000000000000..c3af93f9111d --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentExtensionTests.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache +{ + [TestFixture] + public class PublishedContentExtensionTests : PublishedSnapshotServiceTestBase + { + private const string XmlContent = @" + + +]> + + +"; + + [SetUp] + public override void Setup() + { + base.Setup(); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + XmlContent, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + // configure inheritance for content types + var baseType = new ContentType(TestHelper.ShortStringHelper, -1) { Alias = "Base" }; + contentTypes[0].AddContentType(baseType); + + InitializedCache(kits, contentTypes, dataTypes); + } + + [Test] + public void IsDocumentType_NonRecursive_ActualType_ReturnsTrue() + { + var publishedContent = GetContent(1100); + Assert.That(publishedContent.IsDocumentType("Inherited", false)); + } + + [Test] + public void IsDocumentType_NonRecursive_BaseType_ReturnsFalse() + { + var publishedContent = GetContent(1100); + Assert.That(publishedContent.IsDocumentType("Base", false), Is.False); + } + + [Test] + public void IsDocumentType_Recursive_ActualType_ReturnsTrue() + { + var publishedContent = GetContent(1100); + Assert.That(publishedContent.IsDocumentType("Inherited", true)); + } + + [Test] + public void IsDocumentType_Recursive_BaseType_ReturnsTrue() + { + var publishedContent = GetContent(1100); + Assert.That(publishedContent.IsDocumentType("Base", true)); + } + + [Test] + public void IsDocumentType_Recursive_InvalidBaseType_ReturnsFalse() + { + var publishedContent = GetContent(1100); + Assert.That(publishedContent.IsDocumentType("invalidbase", true), Is.False); + } + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentLanguageVariantTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentLanguageVariantTests.cs new file mode 100644 index 000000000000..3098dc6752f1 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentLanguageVariantTests.cs @@ -0,0 +1,346 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.PropertyEditors.ValueConverters; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; +using Umbraco.Cms.Tests.Common.Builders; +using Umbraco.Cms.Tests.Common.Builders.Extensions; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache +{ + [TestFixture] + public class PublishedContentLanguageVariantTests : PublishedSnapshotServiceTestBase + { + [SetUp] + public override void Setup() + { + base.Setup(); + + var dataTypes = GetDefaultDataTypes(); + var cache = CreateCache(dataTypes, out ContentType[] contentTypes); + + InitializedCache(cache, contentTypes, dataTypes: dataTypes); + } + + protected override PropertyValueConverterCollection PropertyValueConverterCollection + { + get + { + PropertyValueConverterCollection collection = base.PropertyValueConverterCollection; + return new PropertyValueConverterCollection(() => collection.Append(new TestNoValueValueConverter())); + } + } + + private class TestNoValueValueConverter : SimpleTinyMceValueConverter + { + public override bool IsConverter(IPublishedPropertyType propertyType) + => propertyType.Alias == "noprop"; + + // for this test, we return false for IsValue for this property + public override bool? IsValue(object value, PropertyValueLevel level) => false; + } + + /// + /// Override to mock localization service + /// + /// + /// + /// + protected override ServiceContext CreateServiceContext(IContentType[] contentTypes, IMediaType[] mediaTypes, IDataType[] dataTypes) + { + var serviceContext = base.CreateServiceContext(contentTypes, mediaTypes, dataTypes); + + var localizationService = Mock.Get(serviceContext.LocalizationService); + + var languages = new List + { + new Language(GlobalSettings, "en-US") { Id = 1, CultureName = "English", IsDefault = true }, + new Language(GlobalSettings, "fr") { Id = 2, CultureName = "French" }, + new Language(GlobalSettings, "es") { Id = 3, CultureName = "Spanish", FallbackLanguageId = 1 }, + new Language(GlobalSettings, "it") { Id = 4, CultureName = "Italian", FallbackLanguageId = 3 }, + new Language(GlobalSettings, "de") { Id = 5, CultureName = "German" }, + new Language(GlobalSettings, "da") { Id = 6, CultureName = "Danish", FallbackLanguageId = 8 }, + new Language(GlobalSettings, "sv") { Id = 7, CultureName = "Swedish", FallbackLanguageId = 6 }, + new Language(GlobalSettings, "no") { Id = 8, CultureName = "Norweigan", FallbackLanguageId = 7 }, + new Language(GlobalSettings, "nl") { Id = 9, CultureName = "Dutch", FallbackLanguageId = 1 } + }; + + localizationService.Setup(x => x.GetAllLanguages()).Returns(languages); + localizationService.Setup(x => x.GetLanguageById(It.IsAny())) + .Returns((int id) => languages.SingleOrDefault(y => y.Id == id)); + localizationService.Setup(x => x.GetLanguageByIsoCode(It.IsAny())) + .Returns((string c) => languages.SingleOrDefault(y => y.IsoCode == c)); + + return serviceContext; + } + + /// + /// Creates a content cache + /// + /// + /// + /// + /// + /// Builds a content hierarchy of 3 nodes, each has a different set of cultural properties. + /// The first 2 share the same content type, the last one is a different content type. + /// NOTE: The content items themselves are 'Invariant' but their properties are 'Variant' by culture. + /// Normally in Umbraco this is prohibited but our APIs and database do actually support that behavior. + /// It is simpler to have these tests run this way, else we would need to use WithCultureInfos + /// for each item and pass in name values for all cultures we are supporting and then specify the + /// default VariationContextAccessor.VariationContext value to be a default culture instead of "". + /// + private IEnumerable CreateCache(IDataType[] dataTypes, out ContentType[] contentTypes) + { + var result = new List(); + + var propertyDataTypes = new Dictionary + { + // we only have one data type for this test which will be resolved with string empty. + [string.Empty] = dataTypes[0] + }; + + var contentType1 = new ContentType(ShortStringHelper, -1); + + ContentData item1Data = new ContentDataBuilder() + .WithName("Content 1") + .WithProperties(new PropertyDataBuilder() + .WithPropertyData("welcomeText", "Welcome") + .WithPropertyData("welcomeText", "Welcome", "en-US") + .WithPropertyData("welcomeText", "Willkommen", "de") + .WithPropertyData("welcomeText", "Welkom", "nl") + .WithPropertyData("welcomeText2", "Welcome") + .WithPropertyData("welcomeText2", "Welcome", "en-US") + .WithPropertyData("noprop", "xxx") + .Build()) + // build with a dynamically created content type + .Build(ShortStringHelper, propertyDataTypes, contentType1, "ContentType1"); + + ContentNodeKit item1 = ContentNodeKitBuilder.CreateWithContent( + contentType1.Id, + 1, "-1,1", + draftData: item1Data, + publishedData: item1Data); + + result.Add(item1); + + ContentData item2Data = new ContentDataBuilder() + .WithName("Content 2") + .WithProperties(new PropertyDataBuilder() + .WithPropertyData("welcomeText", "Welcome") + .WithPropertyData("welcomeText", "Welcome", "en-US") + .WithPropertyData("noprop", "xxx") + .Build()) + // build while dynamically updating the same content type + .Build(ShortStringHelper, propertyDataTypes, contentType1); + + ContentNodeKit item2 = ContentNodeKitBuilder.CreateWithContent( + contentType1.Id, + 2, "-1,1,2", + parentContentId: 1, + draftData: item2Data, + publishedData: item2Data); + + result.Add(item2); + + var contentType2 = new ContentType(ShortStringHelper, -1); + + ContentData item3Data = new ContentDataBuilder() + .WithName("Content 3") + .WithProperties(new PropertyDataBuilder() + .WithPropertyData("prop3", "Oxxo") + .WithPropertyData("prop3", "Oxxo", "en-US") + .Build()) + // build with a dynamically created content type + .Build(ShortStringHelper, propertyDataTypes, contentType2, "ContentType2"); + + ContentNodeKit item3 = ContentNodeKitBuilder.CreateWithContent( + contentType2.Id, + 3, "-1,1,2,3", + parentContentId: 2, + draftData: item3Data, + publishedData: item3Data); + + result.Add(item3); + + contentTypes = new[] { contentType1, contentType2 }; + + return result; + } + + [Test] + public void Can_Get_Content_For_Populated_Requested_Language() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First(); + var value = content.Value(Mock.Of(), "welcomeText", "en-US"); + Assert.AreEqual("Welcome", value); + } + + [Test] + public void Can_Get_Content_For_Populated_Requested_Non_Default_Language() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First(); + var value = content.Value(Mock.Of(), "welcomeText", "de"); + Assert.AreEqual("Willkommen", value); + } + + [Test] + public void Do_Not_Get_Content_For_Unpopulated_Requested_Language_Without_Fallback() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First(); + var value = content.Value(Mock.Of(), "welcomeText", "fr"); + Assert.IsNull(value); + } + + [Test] + public void Do_Not_Get_Content_For_Unpopulated_Requested_Language_With_Fallback_Unless_Requested() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First(); + var value = content.Value(Mock.Of(), "welcomeText", "es"); + Assert.IsNull(value); + } + + [Test] + public void Can_Get_Content_For_Unpopulated_Requested_Language_With_Fallback() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First(); + var value = content.Value(PublishedValueFallback, "welcomeText", "es", fallback: Fallback.ToLanguage); + Assert.AreEqual("Welcome", value); + } + + [Test] + public void Can_Get_Content_For_Unpopulated_Requested_Language_With_Fallback_Over_Two_Levels() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First(); + var value = content.Value(PublishedValueFallback, "welcomeText", "it", fallback: Fallback.To(Fallback.Language, Fallback.Ancestors)); + Assert.AreEqual("Welcome", value); + } + + [Test] + public void Do_Not_GetContent_For_Unpopulated_Requested_Language_With_Fallback_Over_That_Loops() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First(); + var value = content.Value(Mock.Of(), "welcomeText", "no", fallback: Fallback.ToLanguage); + Assert.IsNull(value); + } + + [Test] + public void Do_Not_Get_Content_Recursively_Unless_Requested() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First().Children.First(); + var value = content.Value(Mock.Of(), "welcomeText2"); + Assert.IsNull(value); + } + + [Test] + public void Can_Get_Content_Recursively() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First().Children.First(); + var value = content.Value(PublishedValueFallback, "welcomeText2", fallback: Fallback.ToAncestors); + Assert.AreEqual("Welcome", value); + } + + [Test] + public void Do_Not_Get_Content_Recursively_Unless_Requested2() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First().Children.First().Children.First(); + Assert.IsNull(content.GetProperty("welcomeText2")); + var value = content.Value(Mock.Of(), "welcomeText2"); + Assert.IsNull(value); + } + + [Test] + public void Can_Get_Content_Recursively2() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First().Children.First().Children.First(); + Assert.IsNull(content.GetProperty("welcomeText2")); + var value = content.Value(PublishedValueFallback, "welcomeText2", fallback: Fallback.ToAncestors); + Assert.AreEqual("Welcome", value); + } + + [Test] + public void Can_Get_Content_Recursively3() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First().Children.First().Children.First(); + Assert.IsNull(content.GetProperty("noprop")); + var value = content.Value(PublishedValueFallback, "noprop", fallback: Fallback.ToAncestors); + // property has no value - based on the converter + // but we still get the value (ie, the converter would do something) + Assert.AreEqual("xxx", value.ToString()); + } + + [Test] + public void Can_Get_Content_With_Recursive_Priority() + { + VariationContextAccessor.VariationContext = new VariationContext("nl"); + + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First().Children.First(); + + var value = content.Value(PublishedValueFallback, "welcomeText", "nl", fallback: Fallback.To(Fallback.Ancestors, Fallback.Language)); + + // No Dutch value is directly assigned. Check has fallen back to Dutch value from parent. + Assert.AreEqual("Welkom", value); + } + + [Test] + public void Can_Get_Content_With_Fallback_Language_Priority() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First().Children.First(); + + var value = content.Value(PublishedValueFallback, "welcomeText", "nl", fallback: Fallback.ToLanguage); + + // No Dutch value is directly assigned. Check has fallen back to English value from language variant. + Assert.AreEqual("Welcome", value); + } + + [Test] + public void Throws_For_Non_Supported_Fallback() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First().Children.First(); + + Assert.Throws(() => content.Value(PublishedValueFallback, "welcomeText", "nl", fallback: Fallback.To(999))); + } + + [Test] + public void Can_Fallback_To_Default_Value() + { + var snapshot = GetPublishedSnapshot(); + var content = snapshot.Content.GetAtRoot().First().Children.First(); + + // no Dutch value is assigned, so getting null + var value = content.Value(PublishedValueFallback, "welcomeText", "nl"); + Assert.IsNull(value); + + // even if we 'just' provide a default value + value = content.Value(PublishedValueFallback, "welcomeText", "nl", defaultValue: "woop"); + Assert.IsNull(value); + + // but it works with proper fallback settings + value = content.Value(PublishedValueFallback, "welcomeText", "nl", fallback: Fallback.ToDefaultValue, defaultValue: "woop"); + Assert.AreEqual("woop", value); + } + } +} diff --git a/tests/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentTests.cs similarity index 51% rename from tests/Umbraco.Tests/PublishedContent/PublishedContentTests.cs rename to tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentTests.cs index c34d9e7595b3..d7a5a2bc4892 100644 --- a/tests/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedContentTests.cs @@ -1,193 +1,108 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Media; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Core.Templates; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure.Serialization; -using Umbraco.Cms.Tests.Common.Testing; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; using Umbraco.Extensions; -using Umbraco.Tests.TestHelpers; -using Umbraco.Web.Composing; -namespace Umbraco.Tests.PublishedContent +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache { - /// - /// Tests the methods on IPublishedContent using the DefaultPublishedContentStore - /// + [TestFixture] - [UmbracoTest(TypeLoader = UmbracoTestOptions.TypeLoader.PerFixture)] - public class PublishedContentTests : PublishedContentTestBase + public class PublishedContentTests : PublishedSnapshotServiceTestBase { - protected override void Compose() - { - base.Compose(); - _publishedSnapshotAccessorMock = new Mock(); - Builder.Services.AddUnique(_publishedSnapshotAccessorMock.Object); - - Builder.Services.AddUnique(f => new PublishedModelFactory(f.GetRequiredService().GetTypes(), f.GetRequiredService())); - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - - var loggerFactory = NullLoggerFactory.Instance; - var mediaService = Mock.Of(); - var contentTypeBaseServiceProvider = Mock.Of(); - var umbracoContextAccessor = Mock.Of(); - var backOfficeSecurityAccessor = Mock.Of(); - var publishedUrlProvider = Mock.Of(); - var imageSourceParser = new HtmlImageSourceParser(publishedUrlProvider); - var serializer = new ConfigurationEditorJsonSerializer(); - var mediaFileService = new MediaFileManager(Mock.Of(), Mock.Of(), - loggerFactory.CreateLogger(), Mock.Of()); - var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, loggerFactory.CreateLogger(), HostingEnvironment, mediaService, contentTypeBaseServiceProvider, mediaFileService, ShortStringHelper, publishedUrlProvider, serializer); - var linkParser = new HtmlLocalLinkParser(umbracoContextAccessor, publishedUrlProvider); - - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(DataValueEditorFactory), serializer) { Id = 1 }, - new DataType(new TrueFalsePropertyEditor(DataValueEditorFactory, IOHelper), serializer) { Id = 1001 }, - new DataType(new RichTextPropertyEditor(DataValueEditorFactory, backOfficeSecurityAccessor, imageSourceParser, linkParser, pastedImages, IOHelper, Mock.Of()), serializer) { Id = 1002 }, - new DataType(new IntegerPropertyEditor(DataValueEditorFactory), serializer) { Id = 1003 }, - new DataType(new TextboxPropertyEditor(DataValueEditorFactory, IOHelper), serializer) { Id = 1004 }, - new DataType(new MediaPickerPropertyEditor(DataValueEditorFactory, IOHelper), serializer) { Id = 1005 }); - Builder.Services.AddUnique(f => dataTypeService); - } - - protected override void Initialize() - { - base.Initialize(); - - var factory = Factory.GetRequiredService() as PublishedContentTypeFactory; - - // need to specify a custom callback for unit tests - // AutoPublishedContentTypes generates properties automatically - // when they are requested, but we must declare those that we - // explicitely want to be here... + private readonly Guid _node1173Guid = Guid.NewGuid(); + private PublishedModelFactory _publishedModelFactory; + private DataType[] _dataTypes; - IEnumerable CreatePropertyTypes(IPublishedContentType contentType) + [SetUp] + public override void Setup() + { + base.Setup(); + + string xml = PublishedContentXml.PublishedContentTestXml(1234, _node1173Guid); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + _dataTypes = dataTypes; + + // configure the Home content type to be composed of another for tests. + var compositionType = new ContentType(TestHelper.ShortStringHelper, -1) { - // AutoPublishedContentType will auto-generate other properties - yield return factory.CreatePropertyType(contentType, "umbracoNaviHide", 1001); - yield return factory.CreatePropertyType(contentType, "selectedNodes", 1); - yield return factory.CreatePropertyType(contentType, "umbracoUrlAlias", 1); - yield return factory.CreatePropertyType(contentType, "content", 1002); - yield return factory.CreatePropertyType(contentType, "testRecursive", 1); - } + Alias = "MyCompositionAlias" + }; + contentTypes.First(x => x.Alias == "Home").AddContentType(compositionType); - var compositionAliases = new[] { "MyCompositionAlias" }; - var anythingType = new AutoPublishedContentType(Guid.NewGuid(), 0, "anything", compositionAliases, CreatePropertyTypes); - var homeType = new AutoPublishedContentType(Guid.NewGuid(), 0, "home", compositionAliases, CreatePropertyTypes); - ContentTypesCache.GetPublishedContentTypeByAlias = alias => alias.InvariantEquals("home") ? homeType : anythingType; + InitializedCache(kits, contentTypes, dataTypes: dataTypes); } + // override to specify our own factory with custom types + protected override IPublishedModelFactory PublishedModelFactory + => _publishedModelFactory ??= new PublishedModelFactory( + new[] { typeof(Home), typeof(Anything), typeof(CustomDocument) }, + PublishedValueFallback); - protected override TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, ILogger logger, IProfilingLogger profilingLogger , IHostingEnvironment hostingEnvironment) + [PublishedModel("Home")] + internal class Home : PublishedContentModel { - var baseLoader = base.CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, profilingLogger , hostingEnvironment); + public Home(IPublishedContent content, IPublishedValueFallback fallback) + : base(content, fallback) + { } - return new TypeLoader(typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, profilingLogger , false, - // this is so the model factory looks into the test assembly - baseLoader.AssembliesToScan - .Union(new[] { typeof(PublishedContentTests).Assembly }) - .ToList()); + public bool UmbracoNaviHide => this.Value(Mock.Of(), "umbracoNaviHide"); } - private readonly Guid _node1173Guid = Guid.NewGuid(); - private Mock _publishedSnapshotAccessorMock; - - protected override string GetXmlContent(int templateId) - { - return @" - - - - -]> - - - - - 1 - - - This is some content]]> - - - - - - - - - - - - - - - - 1 - - - - - - - - - -"; - } - - internal IPublishedContent GetNode(int id) - { - var ctx = GetUmbracoContext("/test"); - var doc = ctx.Content.GetById(id); - Assert.IsNotNull(doc); - return doc; + [PublishedModel("anything")] + internal class Anything : PublishedContentModel + { + public Anything(IPublishedContent content, IPublishedValueFallback fallback) + : base(content, fallback) + { } + } + + [PublishedModel("CustomDocument")] + internal class CustomDocument : PublishedContentModel + { + public CustomDocument(IPublishedContent content, IPublishedValueFallback fallback) + : base(content, fallback) + { } } [Test] public void GetNodeByIds() { - var ctx = GetUmbracoContext("/test"); - var contentById = ctx.Content.GetById(1173); + var snapshot = GetPublishedSnapshot(); + + var contentById = snapshot.Content.GetById(1173); Assert.IsNotNull(contentById); - var contentByGuid = ctx.Content.GetById(_node1173Guid); + var contentByGuid = snapshot.Content.GetById(_node1173Guid); Assert.IsNotNull(contentByGuid); Assert.AreEqual(contentById.Id, contentByGuid.Id); Assert.AreEqual(contentById.Key, contentByGuid.Key); - contentById = ctx.Content.GetById(666); + contentById = snapshot.Content.GetById(666); Assert.IsNull(contentById); - contentByGuid = ctx.Content.GetById(Guid.NewGuid()); + contentByGuid = snapshot.Content.GetById(Guid.NewGuid()); Assert.IsNull(contentByGuid); } [Test] public void Is_Last_From_Where_Filter_Dynamic_Linq() { - var doc = GetNode(1173); + var doc = GetContent(1173); var items = doc.Children(VariationContextAccessor).Where(x => x.IsVisible(Mock.Of())).ToIndexedArray(); @@ -195,11 +110,11 @@ public void Is_Last_From_Where_Filter_Dynamic_Linq() { if (item.Content.Id != 1178) { - Assert.IsFalse(item.IsLast()); + Assert.IsFalse(item.IsLast(), $"The item {item.Content.Id} is last"); } else { - Assert.IsTrue(item.IsLast()); + Assert.IsTrue(item.IsLast(), $"The item {item.Content.Id} is not last"); } } } @@ -207,7 +122,7 @@ public void Is_Last_From_Where_Filter_Dynamic_Linq() [Test] public void Is_Last_From_Where_Filter() { - var doc = GetNode(1173); + var doc = GetContent(1173); var items = doc .Children(VariationContextAccessor) @@ -243,30 +158,14 @@ public void Is_Last_From_Where_Filter() } } - [PublishedModel("Home")] - internal class Home : PublishedContentModel - { - public Home(IPublishedContent content, IPublishedValueFallback fallback) - : base(content, fallback) - {} - } - - [PublishedModel("anything")] - internal class Anything : PublishedContentModel - { - public Anything(IPublishedContent content, IPublishedValueFallback fallback) - : base(content, fallback) - { } - } - [Test] public void Is_Last_From_Where_Filter2() { - var doc = GetNode(1173); + var doc = GetContent(1173); var ct = doc.ContentType; var items = doc.Children(VariationContextAccessor) - .Select(x => x.CreateModel(Current.PublishedModelFactory)) // linq, returns IEnumerable + .Select(x => x.CreateModel(PublishedModelFactory)) // linq, returns IEnumerable // only way around this is to make sure every IEnumerable extension // explicitely returns a PublishedContentSet, not an IEnumerable @@ -295,7 +194,7 @@ public void Is_Last_From_Where_Filter2() [Test] public void Is_Last_From_Take() { - var doc = GetNode(1173); + var doc = GetContent(1173); var items = doc.Children(VariationContextAccessor).Take(4).ToIndexedArray(); @@ -315,7 +214,7 @@ public void Is_Last_From_Take() [Test] public void Is_Last_From_Skip() { - var doc = GetNode(1173); + var doc = GetContent(1173); foreach (var d in doc.Children(VariationContextAccessor).Skip(1).ToIndexedArray()) { @@ -333,10 +232,10 @@ public void Is_Last_From_Skip() [Test] public void Is_Last_From_Concat() { - var doc = GetNode(1173); + var doc = GetContent(1173); var items = doc.Children(VariationContextAccessor) - .Concat(new[] { GetNode(1175), GetNode(4444) }) + .Concat(new[] { GetContent(1175), GetContent(4444) }) .ToIndexedArray(); foreach (var item in items) @@ -355,7 +254,7 @@ public void Is_Last_From_Concat() [Test] public void Descendants_Ordered_Properly() { - var doc = GetNode(1046); + var doc = GetContent(1046); var expected = new[] { 1046, 1173, 1174, 117, 1177, 1178, 1179, 1176, 1175, 4444, 1172 }; var exindex = 0; @@ -370,9 +269,11 @@ public void Descendants_Ordered_Properly() [Test] public void Get_Property_Value_Recursive() { - var doc = GetNode(1174); - var rVal = doc.Value(Factory.GetRequiredService(), "testRecursive", fallback: Fallback.ToAncestors); - var nullVal = doc.Value(Factory.GetRequiredService(), "DoNotFindThis", fallback: Fallback.ToAncestors); + // TODO: We need to use a different fallback? + + var doc = GetContent(1174); + var rVal = doc.Value(PublishedValueFallback, "testRecursive", fallback: Fallback.ToAncestors); + var nullVal = doc.Value(PublishedValueFallback, "DoNotFindThis", fallback: Fallback.ToAncestors); Assert.AreEqual("This is the recursive val", rVal); Assert.AreEqual(null, nullVal); } @@ -380,17 +281,17 @@ public void Get_Property_Value_Recursive() [Test] public void Get_Property_Value_Uses_Converter() { - var doc = GetNode(1173); + var doc = GetContent(1173); - var propVal = doc.Value(Mock.Of(), "content"); + var propVal = doc.Value(PublishedValueFallback, "content"); Assert.IsInstanceOf(typeof(IHtmlEncodedString), propVal); Assert.AreEqual("
        This is some content
        ", propVal.ToString()); - var propVal2 = doc.Value(Mock.Of(), "content"); + var propVal2 = doc.Value(PublishedValueFallback, "content"); Assert.IsInstanceOf(typeof(IHtmlEncodedString), propVal2); Assert.AreEqual("
        This is some content
        ", propVal2.ToString()); - var propVal3 = doc.Value(Mock.Of(), "Content"); + var propVal3 = doc.Value(PublishedValueFallback, "Content"); Assert.IsInstanceOf(typeof(IHtmlEncodedString), propVal3); Assert.AreEqual("
        This is some content
        ", propVal3.ToString()); } @@ -398,12 +299,12 @@ public void Get_Property_Value_Uses_Converter() [Test] public void Complex_Linq() { - var doc = GetNode(1173); + var doc = GetContent(1173); var result = doc.Ancestors().OrderBy(x => x.Level) .Single() .Descendants(Mock.Of()) - .FirstOrDefault(x => x.Value(Mock.Of(), "selectedNodes", defaultValue: "").Split(',').Contains("1173")); + .FirstOrDefault(x => x.Value(PublishedValueFallback, "selectedNodes", fallback: Fallback.ToDefaultValue, defaultValue: "").Split(',').Contains("1173")); Assert.IsNotNull(result); } @@ -411,16 +312,16 @@ public void Complex_Linq() [Test] public void Children_GroupBy_DocumentTypeAlias() { - var home = new AutoPublishedContentType(Guid.NewGuid(), 22, "Home", new PublishedPropertyType[] { }); - var custom = new AutoPublishedContentType(Guid.NewGuid(), 23, "CustomDocument", new PublishedPropertyType[] { }); - var contentTypes = new Dictionary - { - { home.Alias, home }, - { custom.Alias, custom } - }; - ContentTypesCache.GetPublishedContentTypeByAlias = alias => contentTypes[alias]; + //var home = new AutoPublishedContentType(Guid.NewGuid(), 22, "Home", new PublishedPropertyType[] { }); + //var custom = new AutoPublishedContentType(Guid.NewGuid(), 23, "CustomDocument", new PublishedPropertyType[] { }); + //var contentTypes = new Dictionary + //{ + // { home.Alias, home }, + // { custom.Alias, custom } + //}; + //ContentTypesCache.GetPublishedContentTypeByAlias = alias => contentTypes[alias]; - var doc = GetNode(1046); + var doc = GetContent(1046); var found1 = doc.Children(VariationContextAccessor).GroupBy(x => x.ContentType.Alias).ToArray(); @@ -432,16 +333,16 @@ public void Children_GroupBy_DocumentTypeAlias() [Test] public void Children_Where_DocumentTypeAlias() { - var home = new AutoPublishedContentType(Guid.NewGuid(), 22, "Home", new PublishedPropertyType[] { }); - var custom = new AutoPublishedContentType(Guid.NewGuid(), 23, "CustomDocument", new PublishedPropertyType[] { }); - var contentTypes = new Dictionary - { - { home.Alias, home }, - { custom.Alias, custom } - }; - ContentTypesCache.GetPublishedContentTypeByAlias = alias => contentTypes[alias]; + //var home = new AutoPublishedContentType(Guid.NewGuid(), 22, "Home", new PublishedPropertyType[] { }); + //var custom = new AutoPublishedContentType(Guid.NewGuid(), 23, "CustomDocument", new PublishedPropertyType[] { }); + //var contentTypes = new Dictionary + //{ + // { home.Alias, home }, + // { custom.Alias, custom } + //}; + //ContentTypesCache.GetPublishedContentTypeByAlias = alias => contentTypes[alias]; - var doc = GetNode(1046); + var doc = GetContent(1046); var found1 = doc.Children(VariationContextAccessor).Where(x => x.ContentType.Alias == "CustomDocument"); var found2 = doc.Children(VariationContextAccessor).Where(x => x.ContentType.Alias == "Home"); @@ -453,7 +354,7 @@ public void Children_Where_DocumentTypeAlias() [Test] public void Children_Order_By_Update_Date() { - var doc = GetNode(1173); + var doc = GetContent(1173); var ordered = doc.Children(VariationContextAccessor).OrderBy(x => x.UpdateDate); @@ -468,12 +369,12 @@ public void Children_Order_By_Update_Date() [Test] public void FirstChild() { - var doc = GetNode(1173); // has child nodes + var doc = GetContent(1173); // has child nodes Assert.IsNotNull(doc.FirstChild(Mock.Of())); Assert.IsNotNull(doc.FirstChild(Mock.Of(), x => true)); Assert.IsNotNull(doc.FirstChild(Mock.Of())); - doc = GetNode(1175); // does not have child nodes + doc = GetContent(1175); // does not have child nodes Assert.IsNull(doc.FirstChild(Mock.Of())); Assert.IsNull(doc.FirstChild(Mock.Of(), x => true)); Assert.IsNull(doc.FirstChild(Mock.Of())); @@ -482,7 +383,7 @@ public void FirstChild() [Test] public void FirstChildAsT() { - var doc = GetNode(1046); // has child nodes + var doc = GetContent(1046); // has child nodes var model = doc.FirstChild(Mock.Of(), x => true); // predicate @@ -491,7 +392,7 @@ public void FirstChildAsT() Assert.IsInstanceOf(model); Assert.IsInstanceOf(model); - doc = GetNode(1175); // does not have child nodes + doc = GetContent(1175); // does not have child nodes Assert.IsNull(doc.FirstChild(Mock.Of())); Assert.IsNull(doc.FirstChild(Mock.Of(), x => true)); } @@ -499,7 +400,7 @@ public void FirstChildAsT() [Test] public void IsComposedOf() { - var doc = GetNode(1173); + var doc = GetContent(1173); var isComposedOf = doc.IsComposedOf("MyCompositionAlias"); @@ -509,7 +410,7 @@ public void IsComposedOf() [Test] public void HasProperty() { - var doc = GetNode(1173); + var doc = GetContent(1173); var hasProp = doc.HasProperty(Constants.Conventions.Content.UrlAlias); @@ -519,7 +420,7 @@ public void HasProperty() [Test] public void HasValue() { - var doc = GetNode(1173); + var doc = GetContent(1173); var hasValue = doc.HasValue(Mock.Of(), Constants.Conventions.Content.UrlAlias); var noValue = doc.HasValue(Mock.Of(), "blahblahblah"); @@ -531,7 +432,7 @@ public void HasValue() [Test] public void Ancestors_Where_Visible() { - var doc = GetNode(1174); + var doc = GetContent(1174); var whereVisible = doc.Ancestors().Where(x => x.IsVisible(Mock.Of())); Assert.AreEqual(1, whereVisible.Count()); @@ -541,8 +442,8 @@ public void Ancestors_Where_Visible() [Test] public void Visible() { - var hidden = GetNode(1046); - var visible = GetNode(1173); + var hidden = GetContent(1046); + var visible = GetContent(1173); Assert.IsFalse(hidden.IsVisible(Mock.Of())); Assert.IsTrue(visible.IsVisible(Mock.Of())); @@ -551,7 +452,7 @@ public void Visible() [Test] public void Ancestor_Or_Self() { - var doc = GetNode(1173); + var doc = GetContent(1173); var result = doc.AncestorOrSelf(); @@ -564,7 +465,7 @@ public void Ancestor_Or_Self() [Test] public void U4_4559() { - var doc = GetNode(1174); + var doc = GetContent(1174); var result = doc.AncestorOrSelf(1); Assert.IsNotNull(result); Assert.AreEqual(1046, result.Id); @@ -573,27 +474,27 @@ public void U4_4559() [Test] public void Ancestors_Or_Self() { - var doc = GetNode(1174); + var doc = GetContent(1174); var result = doc.AncestorsOrSelf().ToArray(); Assert.IsNotNull(result); Assert.AreEqual(3, result.Length); - Assert.IsTrue(result.Select(x => ((dynamic)x).GetId()).ContainsAll(new dynamic[] { 1174, 1173, 1046 })); + Assert.IsTrue(result.Select(x => x.Id).ContainsAll(new [] { 1174, 1173, 1046 })); } [Test] public void Ancestors() { - var doc = GetNode(1174); + var doc = GetContent(1174); var result = doc.Ancestors().ToArray(); Assert.IsNotNull(result); Assert.AreEqual(2, result.Length); - Assert.IsTrue(result.Select(x => ((dynamic)x).GetId()).ContainsAll(new dynamic[] { 1173, 1046 })); + Assert.IsTrue(result.Select(x => x.Id).ContainsAll(new [] { 1173, 1046 })); } [Test] @@ -607,12 +508,12 @@ public void IsAncestor() // -- Custom Doc4: 117 (parent 1173) // - Custom Doc3: 1172 (no parent) - var home = GetNode(1173); - var root = GetNode(1046); - var customDoc = GetNode(1178); - var customDoc2 = GetNode(1179); - var customDoc3 = GetNode(1172); - var customDoc4 = GetNode(117); + var home = GetContent(1173); + var root = GetContent(1046); + var customDoc = GetContent(1178); + var customDoc2 = GetContent(1179); + var customDoc3 = GetContent(1172); + var customDoc4 = GetContent(117); Assert.IsTrue(root.IsAncestor(customDoc4)); Assert.IsFalse(root.IsAncestor(customDoc3)); @@ -656,12 +557,12 @@ public void IsAncestorOrSelf() // -- Custom Doc4: 117 (parent 1173) // - Custom Doc3: 1172 (no parent) - var home = GetNode(1173); - var root = GetNode(1046); - var customDoc = GetNode(1178); - var customDoc2 = GetNode(1179); - var customDoc3 = GetNode(1172); - var customDoc4 = GetNode(117); + var home = GetContent(1173); + var root = GetContent(1046); + var customDoc = GetContent(1178); + var customDoc2 = GetContent(1179); + var customDoc3 = GetContent(1172); + var customDoc4 = GetContent(117); Assert.IsTrue(root.IsAncestorOrSelf(customDoc4)); Assert.IsFalse(root.IsAncestorOrSelf(customDoc3)); @@ -699,27 +600,27 @@ public void IsAncestorOrSelf() [Test] public void Descendants_Or_Self() { - var doc = GetNode(1046); + var doc = GetContent(1046); var result = doc.DescendantsOrSelf(Mock.Of()).ToArray(); Assert.IsNotNull(result); Assert.AreEqual(10, result.Count()); - Assert.IsTrue(result.Select(x => ((dynamic)x).GetId()).ContainsAll(new dynamic[] { 1046, 1173, 1174, 1176, 1175 })); + Assert.IsTrue(result.Select(x => x.Id).ContainsAll(new [] { 1046, 1173, 1174, 1176, 1175 })); } [Test] public void Descendants() { - var doc = GetNode(1046); + var doc = GetContent(1046); var result = doc.Descendants(Mock.Of()).ToArray(); Assert.IsNotNull(result); Assert.AreEqual(9, result.Count()); - Assert.IsTrue(result.Select(x => ((dynamic)x).GetId()).ContainsAll(new dynamic[] { 1173, 1174, 1176, 1175, 4444 })); + Assert.IsTrue(result.Select(x => x.Id).ContainsAll(new [] { 1173, 1174, 1176, 1175, 4444 })); } [Test] @@ -733,12 +634,12 @@ public void IsDescendant() // -- Custom Doc4: 117 (parent 1173) // - Custom Doc3: 1172 (no parent) - var home = GetNode(1173); - var root = GetNode(1046); - var customDoc = GetNode(1178); - var customDoc2 = GetNode(1179); - var customDoc3 = GetNode(1172); - var customDoc4 = GetNode(117); + var home = GetContent(1173); + var root = GetContent(1046); + var customDoc = GetContent(1178); + var customDoc2 = GetContent(1179); + var customDoc3 = GetContent(1172); + var customDoc4 = GetContent(117); Assert.IsFalse(root.IsDescendant(root)); Assert.IsFalse(root.IsDescendant(home)); @@ -782,12 +683,12 @@ public void IsDescendantOrSelf() // -- Custom Doc4: 117 (parent 1173) // - Custom Doc3: 1172 (no parent) - var home = GetNode(1173); - var root = GetNode(1046); - var customDoc = GetNode(1178); - var customDoc2 = GetNode(1179); - var customDoc3 = GetNode(1172); - var customDoc4 = GetNode(117); + var home = GetContent(1173); + var root = GetContent(1046); + var customDoc = GetContent(1178); + var customDoc2 = GetContent(1179); + var customDoc3 = GetContent(1172); + var customDoc4 = GetContent(117); Assert.IsTrue(root.IsDescendantOrSelf(root)); Assert.IsFalse(root.IsDescendantOrSelf(home)); @@ -830,39 +731,40 @@ public void SiblingsAndSelf() // --- Level1.1.2: 117 (parent 1173) // --- Level1.1.3: 1177 (parent 1173) // --- Level1.1.4: 1178 (parent 1173) + // ---- Level1.1.4.1: 1179 (parent 1178) // --- Level1.1.5: 1176 (parent 1173) // -- Level1.2: 1175 (parent 1046) // -- Level1.3: 4444 (parent 1046) - var root = GetNode(1046); - var level1_1 = GetNode(1173); - var level1_1_1 = GetNode(1174); - var level1_1_2 = GetNode(117); - var level1_1_3 = GetNode(1177); - var level1_1_4 = GetNode(1178); - var level1_1_5 = GetNode(1176); - var level1_2 = GetNode(1175); - var level1_3 = GetNode(4444); + // - Root : 1172 (no parent) - _publishedSnapshotAccessorMock.Setup(x => x.PublishedSnapshot.Content.GetAtRoot(It.IsAny())).Returns(new []{root}); + var root = GetContent(1046); + var level1_1 = GetContent(1173); + var level1_1_1 = GetContent(1174); + var level1_1_2 = GetContent(117); + var level1_1_3 = GetContent(1177); + var level1_1_4 = GetContent(1178); + var level1_1_5 = GetContent(1176); + var level1_2 = GetContent(1175); + var level1_3 = GetContent(4444); + var root2 = GetContent(1172); - var variationContextAccessor = Factory.GetRequiredService(); - var publishedSnapshot = _publishedSnapshotAccessorMock.Object.PublishedSnapshot; + var publishedSnapshot = GetPublishedSnapshot(); - CollectionAssertAreEqual(new []{root}, root.SiblingsAndSelf(publishedSnapshot, variationContextAccessor)); + CollectionAssertAreEqual(new[] { root, root2 }, root.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor)); - CollectionAssertAreEqual( new []{level1_1, level1_2, level1_3}, level1_1.SiblingsAndSelf(publishedSnapshot, variationContextAccessor)); - CollectionAssertAreEqual( new []{level1_1, level1_2, level1_3}, level1_2.SiblingsAndSelf(publishedSnapshot, variationContextAccessor)); - CollectionAssertAreEqual( new []{level1_1, level1_2, level1_3}, level1_3.SiblingsAndSelf(publishedSnapshot, variationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1, level1_2, level1_3 }, level1_1.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1, level1_2, level1_3 }, level1_2.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1, level1_2, level1_3 }, level1_3.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor)); - CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5}, level1_1_1.SiblingsAndSelf(publishedSnapshot, variationContextAccessor)); - CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5}, level1_1_2.SiblingsAndSelf(publishedSnapshot, variationContextAccessor)); - CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5}, level1_1_3.SiblingsAndSelf(publishedSnapshot, variationContextAccessor)); - CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5}, level1_1_4.SiblingsAndSelf(publishedSnapshot, variationContextAccessor)); - CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5}, level1_1_5.SiblingsAndSelf(publishedSnapshot, variationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5 }, level1_1_1.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5 }, level1_1_2.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5 }, level1_1_3.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5 }, level1_1_4.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_3, level1_1_4, level1_1_5 }, level1_1_5.SiblingsAndSelf(publishedSnapshot, VariationContextAccessor)); } - [Test] + [Test] public void Siblings() { // Structure: @@ -872,40 +774,41 @@ public void Siblings() // --- Level1.1.2: 117 (parent 1173) // --- Level1.1.3: 1177 (parent 1173) // --- Level1.1.4: 1178 (parent 1173) + // ---- Level1.1.4.1: 1179 (parent 1178) // --- Level1.1.5: 1176 (parent 1173) // -- Level1.2: 1175 (parent 1046) // -- Level1.3: 4444 (parent 1046) - var root = GetNode(1046); - var level1_1 = GetNode(1173); - var level1_1_1 = GetNode(1174); - var level1_1_2 = GetNode(117); - var level1_1_3 = GetNode(1177); - var level1_1_4 = GetNode(1178); - var level1_1_5 = GetNode(1176); - var level1_2 = GetNode(1175); - var level1_3 = GetNode(4444); + // - Root : 1172 (no parent) - _publishedSnapshotAccessorMock.Setup(x => x.PublishedSnapshot.Content.GetAtRoot(It.IsAny())).Returns(new []{root}); + var root = GetContent(1046); + var level1_1 = GetContent(1173); + var level1_1_1 = GetContent(1174); + var level1_1_2 = GetContent(117); + var level1_1_3 = GetContent(1177); + var level1_1_4 = GetContent(1178); + var level1_1_5 = GetContent(1176); + var level1_2 = GetContent(1175); + var level1_3 = GetContent(4444); + var root2 = GetContent(1172); - var variationContextAccessor = Factory.GetRequiredService(); - var publishedSnapshot = _publishedSnapshotAccessorMock.Object.PublishedSnapshot; + var publishedSnapshot = GetPublishedSnapshot(); - CollectionAssertAreEqual(new IPublishedContent[0], root.Siblings(publishedSnapshot, variationContextAccessor)); + CollectionAssertAreEqual(new[] { root2 }, root.Siblings(publishedSnapshot, VariationContextAccessor)); - CollectionAssertAreEqual( new []{level1_2, level1_3}, level1_1.Siblings(publishedSnapshot, variationContextAccessor)); - CollectionAssertAreEqual( new []{level1_1, level1_3}, level1_2.Siblings(publishedSnapshot, variationContextAccessor)); - CollectionAssertAreEqual( new []{level1_1, level1_2}, level1_3.Siblings(publishedSnapshot, variationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_2, level1_3 }, level1_1.Siblings(publishedSnapshot, VariationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1, level1_3 }, level1_2.Siblings(publishedSnapshot, VariationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1, level1_2 }, level1_3.Siblings(publishedSnapshot, VariationContextAccessor)); - CollectionAssertAreEqual( new []{ level1_1_2, level1_1_3, level1_1_4, level1_1_5}, level1_1_1.Siblings(publishedSnapshot, variationContextAccessor)); - CollectionAssertAreEqual( new []{level1_1_1, level1_1_3, level1_1_4, level1_1_5}, level1_1_2.Siblings(publishedSnapshot, variationContextAccessor)); - CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_4, level1_1_5}, level1_1_3.Siblings(publishedSnapshot, variationContextAccessor)); - CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_3, level1_1_5}, level1_1_4.Siblings(publishedSnapshot, variationContextAccessor)); - CollectionAssertAreEqual( new []{level1_1_1, level1_1_2, level1_1_3, level1_1_4}, level1_1_5.Siblings(publishedSnapshot, variationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1_2, level1_1_3, level1_1_4, level1_1_5 }, level1_1_1.Siblings(publishedSnapshot, VariationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1_1, level1_1_3, level1_1_4, level1_1_5 }, level1_1_2.Siblings(publishedSnapshot, VariationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_4, level1_1_5 }, level1_1_3.Siblings(publishedSnapshot, VariationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_3, level1_1_5 }, level1_1_4.Siblings(publishedSnapshot, VariationContextAccessor)); + CollectionAssertAreEqual(new[] { level1_1_1, level1_1_2, level1_1_3, level1_1_4 }, level1_1_5.Siblings(publishedSnapshot, VariationContextAccessor)); } private void CollectionAssertAreEqual(IEnumerable expected, IEnumerable actual) - where T: IPublishedContent + where T : IPublishedContent { var e = expected.Select(x => x.Id); var a = actual.Select(x => x.Id); @@ -915,37 +818,26 @@ private void CollectionAssertAreEqual(IEnumerable expected, IEnumerable [Test] public void FragmentProperty() { - var factory = Factory.GetRequiredService() as PublishedContentTypeFactory; - IEnumerable CreatePropertyTypes(IPublishedContentType contentType) { - yield return factory.CreatePropertyType(contentType, "detached", 1003); + yield return PublishedContentTypeFactory.CreatePropertyType(contentType, "detached", _dataTypes[0].Id); } - var ct = factory.CreateContentType(Guid.NewGuid(), 0, "alias", CreatePropertyTypes); + var ct = PublishedContentTypeFactory.CreateContentType(Guid.NewGuid(), 0, "alias", CreatePropertyTypes); var pt = ct.GetPropertyType("detached"); var prop = new PublishedElementPropertyBase(pt, null, false, PropertyCacheLevel.None, 5548); Assert.IsInstanceOf(prop.GetValue()); Assert.AreEqual(5548, prop.GetValue()); } - public void Fragment1() - { - var type = ContentTypesCache.Get(PublishedItemType.Content, "detachedSomething"); - var values = new Dictionary(); - var f = new PublishedElement(type, Guid.NewGuid(), values, false); - } - [Test] public void Fragment2() { - var factory = Factory.GetRequiredService() as PublishedContentTypeFactory; - IEnumerable CreatePropertyTypes(IPublishedContentType contentType) { - yield return factory.CreatePropertyType(contentType, "legend", 1004); - yield return factory.CreatePropertyType(contentType, "image", 1005); - yield return factory.CreatePropertyType(contentType, "size", 1003); + yield return PublishedContentTypeFactory.CreatePropertyType(contentType, "legend", _dataTypes[0].Id); + yield return PublishedContentTypeFactory.CreatePropertyType(contentType, "image", _dataTypes[0].Id); + yield return PublishedContentTypeFactory.CreatePropertyType(contentType, "size", _dataTypes[0].Id); } const string val1 = "boom bam"; @@ -954,7 +846,7 @@ IEnumerable CreatePropertyTypes(IPublishedContentType co var guid = Guid.NewGuid(); - var ct = factory.CreateContentType(Guid.NewGuid(), 0, "alias", CreatePropertyTypes); + var ct = PublishedContentTypeFactory.CreateContentType(Guid.NewGuid(), 0, "alias", CreatePropertyTypes); var c = new ImageWithLegendModel(ct, guid, new Dictionary { @@ -967,6 +859,87 @@ IEnumerable CreatePropertyTypes(IPublishedContentType co Assert.AreEqual(val3, c.Size); } + [Test] + public void First() + { + var publishedSnapshot = GetPublishedSnapshot(); + var content = publishedSnapshot.Content.GetAtRoot().First(); + Assert.AreEqual("Home", content.Name(VariationContextAccessor)); + } + + [Test] + public void Distinct() + { + var items = GetContent(1173) + .Children(VariationContextAccessor) + .Distinct() + .Distinct() + .ToIndexedArray(); + + Assert.AreEqual(5, items.Length); + + IndexedArrayItem item = items[0]; + Assert.AreEqual(1174, item.Content.Id); + Assert.IsTrue(item.IsFirst()); + Assert.IsFalse(item.IsLast()); + + item = items[^1]; + Assert.AreEqual(1176, item.Content.Id); + Assert.IsFalse(item.IsFirst()); + Assert.IsTrue(item.IsLast()); + } + + [Test] + public void OfType1() + { + var publishedSnapshot = GetPublishedSnapshot(); + var items = publishedSnapshot.Content.GetAtRoot() + .OfType() + .Distinct() + .ToIndexedArray(); + Assert.AreEqual(1, items.Length); + Assert.IsInstanceOf(items.First().Content); + } + + [Test] + public void OfType2() + { + var publishedSnapshot = GetPublishedSnapshot(); + var content = publishedSnapshot.Content.GetAtRoot() + .OfType() + .Distinct() + .ToIndexedArray(); + Assert.AreEqual(1, content.Length); + Assert.IsInstanceOf(content.First().Content); + } + + [Test] + public void OfType() + { + var content = GetContent(1173) + .Children(VariationContextAccessor) + .OfType() + .First(x => x.UmbracoNaviHide == true); + Assert.AreEqual(1176, content.Id); + } + + [Test] + public void Position() + { + var items = GetContent(1173).Children(VariationContextAccessor) + .Where(x => x.Value(Mock.Of(), "umbracoNaviHide") == 0) + .ToIndexedArray(); + + Assert.AreEqual(3, items.Length); + + Assert.IsTrue(items.First().IsFirst()); + Assert.IsFalse(items.First().IsLast()); + Assert.IsFalse(items.Skip(1).First().IsFirst()); + Assert.IsFalse(items.Skip(1).First().IsLast()); + Assert.IsFalse(items.Skip(2).First().IsFirst()); + Assert.IsTrue(items.Skip(2).First().IsLast()); + } + class ImageWithLegendModel : PublishedElement { public ImageWithLegendModel(IPublishedContentType contentType, Guid fragmentKey, Dictionary values, bool previewing) @@ -980,5 +953,31 @@ public ImageWithLegendModel(IPublishedContentType contentType, Guid fragmentKey, public int Size => this.Value(Mock.Of(), "size"); } + + //[PublishedModel("ContentType2")] + //public class ContentType2 : PublishedContentModel + //{ + // #region Plumbing + + // public ContentType2(IPublishedContent content, IPublishedValueFallback fallback) + // : base(content, fallback) + // { } + + // #endregion + + // public int Prop1 => this.Value(Mock.Of(), "prop1"); + //} + + //[PublishedModel("ContentType2Sub")] + //public class ContentType2Sub : ContentType2 + //{ + // #region Plumbing + + // public ContentType2Sub(IPublishedContent content, IPublishedValueFallback fallback) + // : base(content, fallback) + // { } + + // #endregion + //} } } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedMediaTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedMediaTests.cs new file mode 100644 index 000000000000..e24383855c8d --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedMediaTests.cs @@ -0,0 +1,242 @@ +using System.Collections.Generic; +using System.Linq; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Strings; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; +using Umbraco.Cms.Infrastructure.Serialization; +using Umbraco.Cms.Tests.Common.Builders; +using Umbraco.Cms.Tests.Common.Builders.Extensions; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; +using Umbraco.Extensions; + + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache +{ + /// + /// Tests the typed extension methods on IPublishedContent using the DefaultPublishedMediaStore + /// + [TestFixture] + public class PublishedMediaTests : PublishedSnapshotServiceTestBase + { + [SetUp] + public override void Setup() + { + base.Setup(); + + var dataTypes = GetDefaultDataTypes().ToList(); + var serializer = new ConfigurationEditorJsonSerializer(); + var rteDataType = new DataType(new VoidEditor("RTE", Mock.Of()), serializer) { Id = 4 }; + dataTypes.Add(rteDataType); + _dataTypes = dataTypes.ToArray(); + + _propertyDataTypes = new() + { + // defaults will just use the first one + [string.Empty] = _dataTypes[0], + + // content uses the RTE + ["content"] = _dataTypes[1] + }; + } + + private Dictionary _propertyDataTypes; + private DataType[] _dataTypes; + + private ContentNodeKit CreateRoot(out MediaType mediaType) + { + mediaType = new MediaType(ShortStringHelper, -1); + + ContentData item1Data = new ContentDataBuilder() + .WithName("Content 1") + .WithProperties(new PropertyDataBuilder() + .WithPropertyData("content", "
        This is some content
        ") + .Build()) + // build with a dynamically created media type + .Build(ShortStringHelper, _propertyDataTypes, mediaType, "image2"); + + ContentNodeKit item1 = ContentNodeKitBuilder.CreateWithContent( + mediaType.Id, + 1, "-1,1", + draftData: item1Data, + publishedData: item1Data); + + return item1; + } + + private IEnumerable CreateChildren( + int startId, + ContentNodeKit parent, + IMediaType mediaType, + int count) + { + for (int i = 0; i < count; i++) + { + var id = startId + i + 1; + + ContentData item1Data = new ContentDataBuilder() + .WithName("Child " + id) + .WithProperties(new PropertyDataBuilder() + .WithPropertyData("content", "
        This is some content
        ") + .Build()) + .Build(); + + var parentPath = parent.Node.Path; + + ContentNodeKit item1 = ContentNodeKitBuilder.CreateWithContent( + mediaType.Id, + id, $"{parentPath},{id}", + draftData: item1Data, + publishedData: item1Data); + + yield return item1; + } + } + + private void InitializeWithHierarchy( + out int rootId, + out IReadOnlyList firstLevelChildren, + out IReadOnlyList secondLevelChildren) + { + var cache = new List(); + var root = CreateRoot(out MediaType mediaType); + firstLevelChildren = CreateChildren(10, root, mediaType, 3).ToList(); + secondLevelChildren = CreateChildren(20, firstLevelChildren[0], mediaType, 3).ToList(); + cache.Add(root); + cache.AddRange(firstLevelChildren); + cache.AddRange(secondLevelChildren); + InitializedCache(null, null, _dataTypes, cache, new[] { mediaType }); + rootId = root.Node.Id; + } + + [Test] + public void Get_Property_Value_Uses_Converter() + { + var cache = CreateRoot(out MediaType mediaType); + InitializedCache(null, null, _dataTypes.ToArray(), new[] { cache }, new[] { mediaType }); + + var publishedMedia = GetMedia(1); + + var propVal = publishedMedia.Value(PublishedValueFallback, "content"); + Assert.IsInstanceOf(propVal); + Assert.AreEqual("
        This is some content
        ", propVal.ToString()); + + var propVal2 = publishedMedia.Value(PublishedValueFallback, "content"); + Assert.IsInstanceOf(propVal2); + Assert.AreEqual("
        This is some content
        ", propVal2.ToString()); + + var propVal3 = publishedMedia.Value(PublishedValueFallback, "Content"); + Assert.IsInstanceOf(propVal3); + Assert.AreEqual("
        This is some content
        ", propVal3.ToString()); + } + + [Test] + public void Children() + { + InitializeWithHierarchy( + out var rootId, + out IReadOnlyList firstLevelChildren, + out IReadOnlyList secondLevelChildren); + + var publishedMedia = GetMedia(rootId); + + var rootChildren = publishedMedia.Children(VariationContextAccessor); + Assert.IsTrue(rootChildren.Select(x => x.Id).ContainsAll(firstLevelChildren.Select(x => x.Node.Id))); + + var publishedChild1 = GetMedia(firstLevelChildren[0].Node.Id); + var subChildren = publishedChild1.Children(VariationContextAccessor); + Assert.IsTrue(subChildren.Select(x => x.Id).ContainsAll(secondLevelChildren.Select(x => x.Node.Id))); + } + + [Test] + public void Descendants() + { + InitializeWithHierarchy( + out var rootId, + out IReadOnlyList firstLevelChildren, + out IReadOnlyList secondLevelChildren); + + var publishedMedia = GetMedia(rootId); + var rootDescendants = publishedMedia.Descendants(VariationContextAccessor); + + var descendentIds = firstLevelChildren.Select(x => x.Node.Id).Concat(secondLevelChildren.Select(x => x.Node.Id)); + + Assert.IsTrue(rootDescendants.Select(x => x.Id).ContainsAll(descendentIds)); + + var publishedChild1 = GetMedia(firstLevelChildren[0].Node.Id); + var subDescendants = publishedChild1.Descendants(VariationContextAccessor); + Assert.IsTrue(subDescendants.Select(x => x.Id).ContainsAll(secondLevelChildren.Select(x => x.Node.Id))); + } + + [Test] + public void DescendantsOrSelf() + { + InitializeWithHierarchy( + out var rootId, + out IReadOnlyList firstLevelChildren, + out IReadOnlyList secondLevelChildren); + + var publishedMedia = GetMedia(rootId); + var rootDescendantsOrSelf = publishedMedia.DescendantsOrSelf(VariationContextAccessor); + var descendentAndSelfIds = firstLevelChildren.Select(x => x.Node.Id) + .Concat(secondLevelChildren.Select(x => x.Node.Id)) + .Append(rootId); + + Assert.IsTrue(rootDescendantsOrSelf.Select(x => x.Id).ContainsAll(descendentAndSelfIds)); + + var publishedChild1 = GetMedia(firstLevelChildren[0].Node.Id); + var subDescendantsOrSelf = publishedChild1.DescendantsOrSelf(VariationContextAccessor); + Assert.IsTrue(subDescendantsOrSelf.Select(x => x.Id).ContainsAll( + secondLevelChildren.Select(x => x.Node.Id).Append(firstLevelChildren[0].Node.Id))); + } + + [Test] + public void Parent() + { + InitializeWithHierarchy( + out var rootId, + out IReadOnlyList firstLevelChildren, + out IReadOnlyList secondLevelChildren); + + var publishedMedia = GetMedia(rootId); + Assert.AreEqual(null, publishedMedia.Parent); + + var publishedChild1 = GetMedia(firstLevelChildren[0].Node.Id); + Assert.AreEqual(publishedMedia.Id, publishedChild1.Parent.Id); + + var publishedSubChild1 = GetMedia(secondLevelChildren[0].Node.Id); + Assert.AreEqual(firstLevelChildren[0].Node.Id, publishedSubChild1.Parent.Id); + } + + [Test] + public void Ancestors() + { + InitializeWithHierarchy( + out var rootId, + out IReadOnlyList firstLevelChildren, + out IReadOnlyList secondLevelChildren); + + var publishedSubChild1 = GetMedia(secondLevelChildren[0].Node.Id); + Assert.IsTrue(publishedSubChild1.Ancestors().Select(x => x.Id) + .ContainsAll(new[] { firstLevelChildren[0].Node.Id, rootId })); + } + + [Test] + public void AncestorsOrSelf() + { + InitializeWithHierarchy( + out var rootId, + out IReadOnlyList firstLevelChildren, + out IReadOnlyList secondLevelChildren); + + var publishedSubChild1 = GetMedia(secondLevelChildren[0].Node.Id); + Assert.IsTrue(publishedSubChild1.AncestorsOrSelf().Select(x => x.Id) + .ContainsAll(new[] { secondLevelChildren[0].Node.Id, firstLevelChildren[0].Node.Id, rootId })); + } + + + } +} diff --git a/tests/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedSnapshotServiceCollectionTests.cs similarity index 59% rename from tests/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs rename to tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedSnapshotServiceCollectionTests.cs index 17e78647f24d..532c7ccf4b0c 100644 --- a/tests/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedSnapshotServiceCollectionTests.cs @@ -1,77 +1,30 @@ using System; using System.Collections.Generic; -using System.Data; using System.Linq; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; -using Moq; using NUnit.Framework; -using Umbraco.Cms.Core; using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.Logging; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Services.Changes; -using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.PublishedCache; using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; -using Umbraco.Cms.Infrastructure.Serialization; -using Umbraco.Cms.Tests.Common; +using Umbraco.Cms.Tests.Common.Builders; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; using Umbraco.Extensions; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing.Objects; -using Umbraco.Web.Composing; -namespace Umbraco.Tests.PublishedContent +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache { [TestFixture] - public class NuCacheChildrenTests + public class PublishedSnapshotServiceCollectionTests : PublishedSnapshotServiceTestBase { - private IPublishedModelFactory PublishedModelFactory { get; } = new NoopPublishedModelFactory(); - private IVariationContextAccessor VariationContextAccessor { get; } = TestHelper.VariationContextAccessor; - - private IPublishedSnapshotService _snapshotService; - private IVariationContextAccessor _variationAccesor; - private IPublishedSnapshotAccessor _snapshotAccessor; private ContentType _contentTypeInvariant; private ContentType _contentTypeVariant; - private TestDataSource _source; - private IContentCacheDataSerializerFactory _contentNestedDataSerializerFactory; - - [TearDown] - public void Teardown() - { - _snapshotService?.Dispose(); - } + private ContentType[] _contentTypes; - private void Init(Func> kits) + [SetUp] + public override void Setup() { - var factory = Mock.Of(); - Current.Factory = factory; - - var hostingEnvironment = Mock.Of(); - - Mock.Get(factory).Setup(x => x.GetService(typeof(IPublishedModelFactory))).Returns(PublishedModelFactory); - - var runtime = Mock.Of(); - Mock.Get(runtime).Setup(x => x.Level).Returns(RuntimeLevel.Run); - - var serializer = new ConfigurationEditorJsonSerializer(); - - // create data types, property types and content types - var dataType = new DataType(new VoidEditor("Editor", Mock.Of()), serializer) { Id = 3 }; - - var dataTypes = new[] - { - dataType - }; + base.Setup(); var propertyType = new PropertyType(TestHelper.ShortStringHelper, "Umbraco.Void.Editor", ValueStorageType.Nvarchar) { Alias = "prop", DataTypeId = 3, Variations = ContentVariation.Nothing }; _contentTypeInvariant = new ContentType(TestHelper.ShortStringHelper, -1) { Id = 2, Alias = "itype", Variations = ContentVariation.Nothing }; @@ -81,94 +34,11 @@ private void Init(Func> kits) _contentTypeVariant = new ContentType(TestHelper.ShortStringHelper, -1) { Id = 3, Alias = "vtype", Variations = ContentVariation.Culture }; _contentTypeVariant.AddPropertyType(propertyType); - var contentTypes = new[] + _contentTypes = new[] { _contentTypeInvariant, _contentTypeVariant }; - - var contentTypeService = new Mock(); - contentTypeService.Setup(x => x.GetAll()).Returns(contentTypes); - contentTypeService.Setup(x => x.GetAll(It.IsAny())).Returns(contentTypes); - - var mediaTypeService = new Mock(); - mediaTypeService.Setup(x => x.GetAll()).Returns(Enumerable.Empty()); - mediaTypeService.Setup(x => x.GetAll(It.IsAny())).Returns(Enumerable.Empty()); - - var contentTypeServiceBaseFactory = new Mock(); - contentTypeServiceBaseFactory.Setup(x => x.For(It.IsAny())).Returns(contentTypeService.Object); - - var dataTypeService = Mock.Of(); - Mock.Get(dataTypeService).Setup(x => x.GetAll()).Returns(dataTypes); - - // create a service context - var serviceContext = ServiceContext.CreatePartial( - dataTypeService: dataTypeService, - memberTypeService: Mock.Of(), - memberService: Mock.Of(), - contentTypeService: contentTypeService.Object, - mediaTypeService: mediaTypeService.Object, - localizationService: Mock.Of(), - domainService: Mock.Of() - ); - - // create a scope provider - var scopeProvider = new Mock(); - scopeProvider - .Setup(x => x.CreateScope( - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny())) - .Returns(Mock.Of); - - // create a published content type factory - var contentTypeFactory = new PublishedContentTypeFactory( - PublishedModelFactory, - new PropertyValueConverterCollection(Array.Empty()), - dataTypeService); - - // create accessors - _variationAccesor = new TestVariationContextAccessor(); - _snapshotAccessor = new TestPublishedSnapshotAccessor(); - - // create a data source for NuCache - _source = new TestDataSource(kits()); - _contentNestedDataSerializerFactory = new JsonContentNestedDataSerializerFactory(); - - var typeFinder = TestHelper.GetTypeFinder(); - - var globalSettings = new GlobalSettings(); - var nuCacheSettings = new NuCacheSettings(); - - // at last, create the complete NuCache snapshot service! - var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; - _snapshotService = new PublishedSnapshotService( - options, - null, - serviceContext, - contentTypeFactory, - _snapshotAccessor, - _variationAccesor, - Mock.Of(), - NullLoggerFactory.Instance, - scopeProvider.Object, - _source, - new TestDefaultCultureAccessor(), - Options.Create(globalSettings), - Mock.Of(), - PublishedModelFactory, - hostingEnvironment, - Options.Create(nuCacheSettings), - _contentNestedDataSerializerFactory); - - - // invariant is the current default - _variationAccesor.VariationContext = new VariationContext(); - - Mock.Get(factory).Setup(x => x.GetService(typeof(IVariationContextAccessor))).Returns(_variationAccesor); } private IEnumerable GetNestedVariantKits() @@ -224,25 +94,13 @@ private ContentNodeKit CreateInvariantKit(int id, int parentId, int sortOrder, D var level = path.Count(x => x == ','); var now = DateTime.Now; - var contentData = new ContentData - { - Name = "N" + id, - Published = true, - TemplateId = 0, - VersionId = 1, - VersionDate = now, - WriterId = 0, - Properties = new Dictionary(), - CultureInfos = new Dictionary() - }; + var contentData = ContentDataBuilder.CreateBasic("N" + id, now); - return new ContentNodeKit - { - ContentTypeId = _contentTypeInvariant.Id, - Node = new ContentNode(id, Guid.NewGuid(), level, path, sortOrder, parentId, DateTime.Now, 0), - DraftData = null, - PublishedData = contentData - }; + return ContentNodeKitBuilder.CreateWithContent( + _contentTypeInvariant.Id, + id, path, sortOrder, level, parentId, 0, Guid.NewGuid(), DateTime.Now, + null, + contentData); } private IEnumerable GetVariantKits() @@ -289,23 +147,16 @@ private ContentNodeKit CreateVariantKit(int id, int parentId, int sortOrder, Dic var level = path.Count(x => x == ','); var now = DateTime.Now; - return new ContentNodeKit - { - ContentTypeId = _contentTypeVariant.Id, - Node = new ContentNode(id, Guid.NewGuid(), level, path, sortOrder, parentId, DateTime.Now, 0), - DraftData = null, - PublishedData = new ContentData - { - Name = "N" + id, - Published = true, - TemplateId = 0, - VersionId = 1, - VersionDate = now, - WriterId = 0, - Properties = new Dictionary(), - CultureInfos = GetCultureInfos(id, now) - } - }; + var contentData = ContentDataBuilder.CreateVariant( + "N" + id, + GetCultureInfos(id, now), + now); + + return ContentNodeKitBuilder.CreateWithContent( + contentTypeId: _contentTypeVariant.Id, + id: id, path: path, sortOrder: sortOrder, level: level, parentContentId: parentId, + draftData: null, + publishedData: contentData); } private IEnumerable GetVariantWithDraftKits() @@ -334,28 +185,20 @@ ContentNodeKit CreateKit(int id, int parentId, int sortOrder) var level = path.Count(x => x == ','); var now = DateTime.Now; - ContentData CreateContentData(bool published) => new ContentData - { - Name = "N" + id, - Published = published, - TemplateId = 0, - VersionId = 1, - VersionDate = now, - WriterId = 0, - Properties = new Dictionary(), - CultureInfos = GetCultureInfos(id, now) - }; + ContentData CreateContentData(bool published) => ContentDataBuilder.CreateVariant( + "N" + id, + GetCultureInfos(id, now), + now, + published); var withDraft = id % 2 == 0; var withPublished = !withDraft; - return new ContentNodeKit - { - ContentTypeId = _contentTypeVariant.Id, - Node = new ContentNode(id, Guid.NewGuid(), level, path, sortOrder, parentId, DateTime.Now, 0), - DraftData = withDraft ? CreateContentData(false) : null, - PublishedData = withPublished ? CreateContentData(true) : null - }; + return ContentNodeKitBuilder.CreateWithContent( + contentTypeId: _contentTypeVariant.Id, + id: id, path: path, sortOrder: sortOrder, level: level, parentContentId: parentId, + draftData: withDraft ? CreateContentData(false) : null, + publishedData: withPublished ? CreateContentData(true) : null); } yield return CreateKit(1, -1, 1); @@ -379,10 +222,9 @@ ContentNodeKit CreateKit(int id, int parentId, int sortOrder) [Test] public void EmptyTest() { - Init(() => Enumerable.Empty()); + InitializedCache(Array.Empty(), _contentTypes); - var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - _snapshotAccessor.PublishedSnapshot = snapshot; + var snapshot = GetPublishedSnapshot(); var documents = snapshot.Content.GetAtRoot().ToArray(); Assert.AreEqual(0, documents.Length); @@ -391,37 +233,35 @@ public void EmptyTest() [Test] public void ChildrenTest() { - Init(GetInvariantKits); + InitializedCache(GetInvariantKits(), _contentTypes); - var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - _snapshotAccessor.PublishedSnapshot = snapshot; + var snapshot = GetPublishedSnapshot(); var documents = snapshot.Content.GetAtRoot().ToArray(); AssertDocuments(documents, "N1", "N2", "N3"); - documents = snapshot.Content.GetById(1).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(1).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N4", "N5", "N6"); - documents = snapshot.Content.GetById(2).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(2).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N9", "N8", "N7"); - documents = snapshot.Content.GetById(3).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(3).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N10"); - documents = snapshot.Content.GetById(4).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(4).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N11", "N12"); - documents = snapshot.Content.GetById(10).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(10).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents); } [Test] public void ParentTest() { - Init(GetInvariantKits); + InitializedCache(GetInvariantKits(), _contentTypes); - var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - _snapshotAccessor.PublishedSnapshot = snapshot; + var snapshot = GetPublishedSnapshot(); Assert.IsNull(snapshot.Content.GetById(1).Parent); Assert.IsNull(snapshot.Content.GetById(2).Parent); @@ -444,40 +284,27 @@ public void ParentTest() [Test] public void MoveToRootTest() { - Init(GetInvariantKits); + InitializedCache(GetInvariantKits(), _contentTypes); // get snapshot - var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - _snapshotAccessor.PublishedSnapshot = snapshot; + var snapshot = GetPublishedSnapshot(); // do some changes - var kit = _source.Kits[10]; - _source.Kits[10] = new ContentNodeKit - { - ContentTypeId = 2, - Node = new ContentNode(kit.Node.Id, Guid.NewGuid(), 1, "-1,10", 4, -1, DateTime.Now, 0), - DraftData = null, - PublishedData = new ContentData - { - Name = kit.PublishedData.Name, - Published = true, - TemplateId = 0, - VersionId = 1, - VersionDate = DateTime.Now, - WriterId = 0, - Properties = new Dictionary(), - CultureInfos = new Dictionary() - } - }; + var kit = NuCacheContentService.ContentKits[10]; + NuCacheContentService.ContentKits[10] = ContentNodeKitBuilder.CreateWithContent( + contentTypeId: _contentTypeInvariant.Id, + id: kit.Node.Id, path: "-1,10", sortOrder: 4, level: 1, parentContentId: -1, + draftData: null, + publishedData: ContentDataBuilder.CreateBasic(kit.PublishedData.Name)); // notify - _snapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(10, Guid.Empty, TreeChangeTypes.RefreshBranch) }, out _, out _); + SnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(10, Guid.Empty, TreeChangeTypes.RefreshBranch) }, out _, out _); // changes that *I* make are immediately visible on the current snapshot var documents = snapshot.Content.GetAtRoot().ToArray(); AssertDocuments(documents, "N1", "N2", "N3", "N10"); - documents = snapshot.Content.GetById(3).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(3).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents); Assert.IsNull(snapshot.Content.GetById(10).Parent); @@ -486,40 +313,27 @@ public void MoveToRootTest() [Test] public void MoveFromRootTest() { - Init(GetInvariantKits); + InitializedCache(GetInvariantKits(), _contentTypes); // get snapshot - var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - _snapshotAccessor.PublishedSnapshot = snapshot; + var snapshot = GetPublishedSnapshot(); // do some changes - var kit = _source.Kits[1]; - _source.Kits[1] = new ContentNodeKit - { - ContentTypeId = 2, - Node = new ContentNode(kit.Node.Id, Guid.NewGuid(), 1, "-1,3,10,1", 1, 10, DateTime.Now, 0), - DraftData = null, - PublishedData = new ContentData - { - Name = kit.PublishedData.Name, - Published = true, - TemplateId = 0, - VersionId = 1, - VersionDate = DateTime.Now, - WriterId = 0, - Properties = new Dictionary(), - CultureInfos = new Dictionary() - } - }; + var kit = NuCacheContentService.ContentKits[1]; + NuCacheContentService.ContentKits[1] = ContentNodeKitBuilder.CreateWithContent( + contentTypeId: _contentTypeInvariant.Id, + id: kit.Node.Id, path: "-1,3,10,1", sortOrder: 1, level: 1, parentContentId: 10, + draftData: null, + publishedData: ContentDataBuilder.CreateBasic(kit.PublishedData.Name)); // notify - _snapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(1, Guid.Empty, TreeChangeTypes.RefreshBranch) }, out _, out _); + SnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(1, Guid.Empty, TreeChangeTypes.RefreshBranch) }, out _, out _); // changes that *I* make are immediately visible on the current snapshot var documents = snapshot.Content.GetAtRoot().ToArray(); AssertDocuments(documents, "N2", "N3"); - documents = snapshot.Content.GetById(10).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(10).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N1"); Assert.AreEqual(10, snapshot.Content.GetById(1).Parent?.Id); @@ -528,166 +342,81 @@ public void MoveFromRootTest() [Test] public void ReOrderTest() { - Init(GetInvariantKits); + InitializedCache(GetInvariantKits(), _contentTypes); // get snapshot - var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - _snapshotAccessor.PublishedSnapshot = snapshot; + var snapshot = GetPublishedSnapshot(); // do some changes - var kit = _source.Kits[7]; - _source.Kits[7] = new ContentNodeKit - { - ContentTypeId = 2, - Node = new ContentNode(kit.Node.Id, Guid.NewGuid(), kit.Node.Level, kit.Node.Path, 1, kit.Node.ParentContentId, DateTime.Now, 0), - DraftData = null, - PublishedData = new ContentData - { - Name = kit.PublishedData.Name, - Published = true, - TemplateId = 0, - VersionId = 1, - VersionDate = DateTime.Now, - WriterId = 0, - Properties = new Dictionary(), - CultureInfos = new Dictionary() - } - }; - - kit = _source.Kits[8]; - _source.Kits[8] = new ContentNodeKit - { - ContentTypeId = 2, - Node = new ContentNode(kit.Node.Id, Guid.NewGuid(), kit.Node.Level, kit.Node.Path, 3, kit.Node.ParentContentId, DateTime.Now, 0), - DraftData = null, - PublishedData = new ContentData - { - Name = kit.PublishedData.Name, - Published = true, - TemplateId = 0, - VersionId = 1, - VersionDate = DateTime.Now, - WriterId = 0, - Properties = new Dictionary(), - CultureInfos = new Dictionary() - } - }; - - kit = _source.Kits[9]; - _source.Kits[9] = new ContentNodeKit - { - ContentTypeId = 2, - Node = new ContentNode(kit.Node.Id, Guid.NewGuid(), kit.Node.Level, kit.Node.Path, 2, kit.Node.ParentContentId, DateTime.Now, 0), - DraftData = null, - PublishedData = new ContentData - { - Name = kit.PublishedData.Name, - Published = true, - TemplateId = 0, - VersionId = 1, - VersionDate = DateTime.Now, - WriterId = 0, - Properties = new Dictionary(), - CultureInfos = new Dictionary() - } - }; + var kit = NuCacheContentService.ContentKits[7]; + NuCacheContentService.ContentKits[7] = ContentNodeKitBuilder.CreateWithContent( + contentTypeId: _contentTypeInvariant.Id, + id: kit.Node.Id, path: kit.Node.Path, sortOrder: 1, level: kit.Node.Level, parentContentId: kit.Node.ParentContentId, + draftData: null, + publishedData: ContentDataBuilder.CreateBasic(kit.PublishedData.Name)); + + kit = NuCacheContentService.ContentKits[8]; + NuCacheContentService.ContentKits[8] = ContentNodeKitBuilder.CreateWithContent( + contentTypeId: _contentTypeInvariant.Id, + id: kit.Node.Id, path: kit.Node.Path, sortOrder: 3, level: kit.Node.Level, parentContentId: kit.Node.ParentContentId, + draftData: null, + publishedData: ContentDataBuilder.CreateBasic(kit.PublishedData.Name)); + + kit = NuCacheContentService.ContentKits[9]; + NuCacheContentService.ContentKits[9] = ContentNodeKitBuilder.CreateWithContent( + contentTypeId: _contentTypeInvariant.Id, + id: kit.Node.Id, path: kit.Node.Path, sortOrder: 2, level: kit.Node.Level, parentContentId: kit.Node.ParentContentId, + draftData: null, + publishedData: ContentDataBuilder.CreateBasic(kit.PublishedData.Name)); // notify - _snapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(kit.Node.ParentContentId, Guid.Empty, TreeChangeTypes.RefreshBranch) }, out _, out _); + SnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(kit.Node.ParentContentId, Guid.Empty, TreeChangeTypes.RefreshBranch) }, out _, out _); // changes that *I* make are immediately visible on the current snapshot - var documents = snapshot.Content.GetById(kit.Node.ParentContentId).Children(_variationAccesor).ToArray(); + var documents = snapshot.Content.GetById(kit.Node.ParentContentId).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N7", "N9", "N8"); } [Test] public void MoveTest() { - Init(GetInvariantKits); + InitializedCache(GetInvariantKits(), _contentTypes); // get snapshot - var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - _snapshotAccessor.PublishedSnapshot = snapshot; + var snapshot = GetPublishedSnapshot(); // do some changes - var kit = _source.Kits[4]; - _source.Kits[4] = new ContentNodeKit - { - ContentTypeId = 2, - Node = new ContentNode(kit.Node.Id, Guid.NewGuid(), kit.Node.Level, kit.Node.Path, 2, kit.Node.ParentContentId, DateTime.Now, 0), - DraftData = null, - PublishedData = new ContentData - { - Name = kit.PublishedData.Name, - Published = true, - TemplateId = 0, - VersionId = 1, - VersionDate = DateTime.Now, - WriterId = 0, - Properties = new Dictionary(), - CultureInfos = new Dictionary() - } - }; - - kit = _source.Kits[5]; - _source.Kits[5] = new ContentNodeKit - { - ContentTypeId = 2, - Node = new ContentNode(kit.Node.Id, Guid.NewGuid(), kit.Node.Level, kit.Node.Path, 3, kit.Node.ParentContentId, DateTime.Now, 0), - DraftData = null, - PublishedData = new ContentData - { - Name = kit.PublishedData.Name, - Published = true, - TemplateId = 0, - VersionId = 1, - VersionDate = DateTime.Now, - WriterId = 0, - Properties = new Dictionary(), - CultureInfos = new Dictionary() - } - }; - - kit = _source.Kits[6]; - _source.Kits[6] = new ContentNodeKit - { - ContentTypeId = 2, - Node = new ContentNode(kit.Node.Id, Guid.NewGuid(), kit.Node.Level, kit.Node.Path, 4, kit.Node.ParentContentId, DateTime.Now, 0), - DraftData = null, - PublishedData = new ContentData - { - Name = kit.PublishedData.Name, - Published = true, - TemplateId = 0, - VersionId = 1, - VersionDate = DateTime.Now, - WriterId = 0, - Properties = new Dictionary(), - CultureInfos = new Dictionary() - } - }; - - kit = _source.Kits[7]; - _source.Kits[7] = new ContentNodeKit - { - ContentTypeId = 2, - Node = new ContentNode(kit.Node.Id, Guid.NewGuid(), kit.Node.Level, "-1,1,7", 1, 1, DateTime.Now, 0), - DraftData = null, - PublishedData = new ContentData - { - Name = kit.PublishedData.Name, - Published = true, - TemplateId = 0, - VersionId = 1, - VersionDate = DateTime.Now, - WriterId = 0, - Properties = new Dictionary(), - CultureInfos = new Dictionary() - } - }; + var kit = NuCacheContentService.ContentKits[4]; + NuCacheContentService.ContentKits[4] = ContentNodeKitBuilder.CreateWithContent( + contentTypeId: _contentTypeInvariant.Id, + id: kit.Node.Id, path: kit.Node.Path, sortOrder: 2, level: kit.Node.Level, parentContentId: kit.Node.ParentContentId, + draftData: null, + publishedData: ContentDataBuilder.CreateBasic(kit.PublishedData.Name)); + + kit = NuCacheContentService.ContentKits[5]; + NuCacheContentService.ContentKits[5] = ContentNodeKitBuilder.CreateWithContent( + contentTypeId: _contentTypeInvariant.Id, + id: kit.Node.Id, path: kit.Node.Path, sortOrder: 3, level: kit.Node.Level, parentContentId: kit.Node.ParentContentId, + draftData: null, + publishedData: ContentDataBuilder.CreateBasic(kit.PublishedData.Name)); + + kit = NuCacheContentService.ContentKits[6]; + NuCacheContentService.ContentKits[6] = ContentNodeKitBuilder.CreateWithContent( + contentTypeId: _contentTypeInvariant.Id, + id: kit.Node.Id, path: kit.Node.Path, sortOrder: 4, level: kit.Node.Level, parentContentId: kit.Node.ParentContentId, + draftData: null, + publishedData: ContentDataBuilder.CreateBasic(kit.PublishedData.Name)); + ; + + kit = NuCacheContentService.ContentKits[7]; + NuCacheContentService.ContentKits[7] = ContentNodeKitBuilder.CreateWithContent( + contentTypeId: _contentTypeInvariant.Id, + id: kit.Node.Id, path: "-1,1,7", sortOrder: 1, level: kit.Node.Level, parentContentId: 1, + draftData: null, + publishedData: ContentDataBuilder.CreateBasic(kit.PublishedData.Name)); // notify - _snapshotService.Notify(new[] + SnapshotService.Notify(new[] { // removal must come first new ContentCacheRefresher.JsonPayload(2, Guid.Empty, TreeChangeTypes.RefreshBranch), @@ -695,10 +424,10 @@ public void MoveTest() }, out _, out _); // changes that *I* make are immediately visible on the current snapshot - var documents = snapshot.Content.GetById(1).Children(_variationAccesor).ToArray(); + var documents = snapshot.Content.GetById(1).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N7", "N4", "N5", "N6"); - documents = snapshot.Content.GetById(2).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(2).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N9", "N8"); Assert.AreEqual(1, snapshot.Content.GetById(7).Parent?.Id); @@ -712,7 +441,7 @@ public void Clear_Branch_Locked() var paths = new Dictionary { { -1, "-1" } }; - Init(() => new List + InitializedCache(new List { CreateInvariantKit(1, -1, 1, paths), // first level CreateInvariantKit(2, 1, 1, paths), // second level @@ -727,19 +456,18 @@ public void Clear_Branch_Locked() CreateInvariantKit(8, 5, 4, paths), CreateInvariantKit(9, 5, 5, paths), CreateInvariantKit(10, 5, 6, paths) - }); + }, _contentTypes); // get snapshot - var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - _snapshotAccessor.PublishedSnapshot = snapshot; + var snapshot = GetPublishedSnapshot(); - var snapshotService = (PublishedSnapshotService)_snapshotService; + var snapshotService = (PublishedSnapshotService)SnapshotService; var contentStore = snapshotService.GetContentStore(); //This will set a flag to force creating a new Gen next time the store is locked (i.e. In Notify) contentStore.CreateSnapshot(); // notify - which ensures there are 2 generations in the cache meaning each LinkedNode has a Next value. - _snapshotService.Notify(new[] + SnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(4, Guid.Empty, TreeChangeTypes.RefreshBranch) }, out _, out _); @@ -749,7 +477,7 @@ public void Clear_Branch_Locked() // to a child, we null out the .Value of the LinkedNode within the while loop because we didn't capture // this value before recursing. Assert.DoesNotThrow(() => - _snapshotService.Notify(new[] + SnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(4, Guid.Empty, TreeChangeTypes.RefreshBranch) }, out _, out _)); @@ -758,45 +486,45 @@ public void Clear_Branch_Locked() [Test] public void NestedVariationChildrenTest() { - Init(GetNestedVariantKits); + InitializedCache(GetNestedVariantKits(), _contentTypes); - var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - _snapshotAccessor.PublishedSnapshot = snapshot; + // get snapshot + var snapshot = GetPublishedSnapshot(); //TEST with en-us variation context - _variationAccesor.VariationContext = new VariationContext("en-US"); + VariationContextAccessor.VariationContext = new VariationContext("en-US"); var documents = snapshot.Content.GetAtRoot().ToArray(); AssertDocuments(documents, "N1-en-US"); - documents = snapshot.Content.GetById(1).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(1).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N4", "N7-en-US"); //Get the invariant and list children, there's a variation context so it should return invariant AND en-us variants - documents = snapshot.Content.GetById(4).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(4).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N10-en-US", "N11"); //Get the variant and list children, there's a variation context so it should return invariant AND en-us variants - documents = snapshot.Content.GetById(7).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(7).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N12-en-US", "N13"); //TEST with fr-fr variation context - _variationAccesor.VariationContext = new VariationContext("fr-FR"); + VariationContextAccessor.VariationContext = new VariationContext("fr-FR"); documents = snapshot.Content.GetAtRoot().ToArray(); AssertDocuments(documents, "N1-fr-FR"); - documents = snapshot.Content.GetById(1).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(1).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N4", "N7-fr-FR"); //Get the invariant and list children, there's a variation context so it should return invariant AND en-us variants - documents = snapshot.Content.GetById(4).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(4).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N10-fr-FR", "N11"); //Get the variant and list children, there's a variation context so it should return invariant AND en-us variants - documents = snapshot.Content.GetById(7).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(7).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N12-fr-FR", "N13"); //TEST specific cultures @@ -804,26 +532,26 @@ public void NestedVariationChildrenTest() documents = snapshot.Content.GetAtRoot("fr-FR").ToArray(); AssertDocuments(documents, "N1-fr-FR"); - documents = snapshot.Content.GetById(1).Children(_variationAccesor, "fr-FR").ToArray(); + documents = snapshot.Content.GetById(1).Children(VariationContextAccessor, "fr-FR").ToArray(); AssertDocuments(documents, "N4", "N7-fr-FR"); //NOTE: Returns invariant, this is expected - documents = snapshot.Content.GetById(1).Children(_variationAccesor, "").ToArray(); + documents = snapshot.Content.GetById(1).Children(VariationContextAccessor, "").ToArray(); AssertDocuments(documents, "N4"); //Only returns invariant since that is what was requested - documents = snapshot.Content.GetById(4).Children(_variationAccesor, "fr-FR").ToArray(); + documents = snapshot.Content.GetById(4).Children(VariationContextAccessor, "fr-FR").ToArray(); AssertDocuments(documents, "N10-fr-FR", "N11"); //NOTE: Returns invariant, this is expected - documents = snapshot.Content.GetById(4).Children(_variationAccesor, "").ToArray(); + documents = snapshot.Content.GetById(4).Children(VariationContextAccessor, "").ToArray(); AssertDocuments(documents, "N11"); //Only returns invariant since that is what was requested - documents = snapshot.Content.GetById(7).Children(_variationAccesor, "fr-FR").ToArray(); + documents = snapshot.Content.GetById(7).Children(VariationContextAccessor, "fr-FR").ToArray(); AssertDocuments(documents, "N12-fr-FR", "N13"); //NOTE: Returns invariant, this is expected - documents = snapshot.Content.GetById(7).Children(_variationAccesor, "").ToArray(); + documents = snapshot.Content.GetById(7).Children(VariationContextAccessor, "").ToArray(); AssertDocuments(documents, "N13"); //Only returns invariant since that is what was requested //TEST without variation context // This will actually convert the culture to "" which will be invariant since that's all it will know how to do // This will return a NULL name for culture specific entities because there is no variation context - _variationAccesor.VariationContext = null; + VariationContextAccessor.VariationContext = null; documents = snapshot.Content.GetAtRoot().ToArray(); //will return nothing because there's only variant at root @@ -832,72 +560,72 @@ public void NestedVariationChildrenTest() documents = snapshot.Content.GetAtRoot("fr-FR").ToArray(); Assert.AreEqual(1, documents.Length); - documents = snapshot.Content.GetById(1).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(1).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N4"); //Get the invariant and list children - documents = snapshot.Content.GetById(4).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(4).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N11"); //Get the variant and list children - documents = snapshot.Content.GetById(7).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(7).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N13"); } [Test] public void VariantChildrenTest() { - Init(GetVariantKits); + InitializedCache(GetVariantKits(), _contentTypes); - var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - _snapshotAccessor.PublishedSnapshot = snapshot; + // get snapshot + var snapshot = GetPublishedSnapshot(); - _variationAccesor.VariationContext = new VariationContext("en-US"); + VariationContextAccessor.VariationContext = new VariationContext("en-US"); var documents = snapshot.Content.GetAtRoot().ToArray(); AssertDocuments(documents, "N1-en-US", "N2-en-US", "N3-en-US"); - documents = snapshot.Content.GetById(1).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(1).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N4-en-US", "N5-en-US", "N6-en-US"); - documents = snapshot.Content.GetById(2).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(2).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N9-en-US", "N8-en-US", "N7-en-US"); - documents = snapshot.Content.GetById(3).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(3).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N10-en-US"); - documents = snapshot.Content.GetById(4).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(4).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N11-en-US", "N12-en-US"); - documents = snapshot.Content.GetById(10).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(10).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents); - _variationAccesor.VariationContext = new VariationContext("fr-FR"); + VariationContextAccessor.VariationContext = new VariationContext("fr-FR"); documents = snapshot.Content.GetAtRoot().ToArray(); AssertDocuments(documents, "N1-fr-FR", "N3-fr-FR"); - documents = snapshot.Content.GetById(1).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(1).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N4-fr-FR", "N6-fr-FR"); - documents = snapshot.Content.GetById(2).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(2).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N9-fr-FR", "N7-fr-FR"); - documents = snapshot.Content.GetById(3).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(3).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N10-fr-FR"); - documents = snapshot.Content.GetById(4).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(4).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N12-fr-FR"); - documents = snapshot.Content.GetById(10).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(10).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents); - documents = snapshot.Content.GetById(1).Children(_variationAccesor, "*").ToArray(); + documents = snapshot.Content.GetById(1).Children(VariationContextAccessor, "*").ToArray(); AssertDocuments(documents, "N4-fr-FR", null, "N6-fr-FR"); AssertDocuments("en-US", documents, "N4-en-US", "N5-en-US", "N6-en-US"); - documents = snapshot.Content.GetById(1).Children(_variationAccesor, "en-US").ToArray(); + documents = snapshot.Content.GetById(1).Children(VariationContextAccessor, "en-US").ToArray(); AssertDocuments(documents, "N4-fr-FR", null, "N6-fr-FR"); AssertDocuments("en-US", documents, "N4-en-US", "N5-en-US", "N6-en-US"); @@ -909,32 +637,32 @@ public void VariantChildrenTest() documents = snapshot.Content.GetAtRoot("*").ToArray(); AssertDocuments(documents, "N1-fr-FR", null, "N3-fr-FR"); - documents = snapshot.Content.GetById(1).DescendantsOrSelf(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(1).DescendantsOrSelf(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N1-fr-FR", "N4-fr-FR", "N12-fr-FR", "N6-fr-FR"); - documents = snapshot.Content.GetById(1).DescendantsOrSelf(_variationAccesor, "*").ToArray(); + documents = snapshot.Content.GetById(1).DescendantsOrSelf(VariationContextAccessor, "*").ToArray(); AssertDocuments(documents, "N1-fr-FR", "N4-fr-FR", null /*11*/, "N12-fr-FR", null /*5*/, "N6-fr-FR"); } [Test] public void RemoveTest() { - Init(GetInvariantKits); + InitializedCache(GetInvariantKits(), _contentTypes); - var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - _snapshotAccessor.PublishedSnapshot = snapshot; + // get snapshot + var snapshot = GetPublishedSnapshot(); var documents = snapshot.Content.GetAtRoot().ToArray(); AssertDocuments(documents, "N1", "N2", "N3"); - documents = snapshot.Content.GetById(1).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(1).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N4", "N5", "N6"); - documents = snapshot.Content.GetById(2).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(2).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N9", "N8", "N7"); // notify - _snapshotService.Notify(new[] + SnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(3, Guid.Empty, TreeChangeTypes.Remove), // remove last new ContentCacheRefresher.JsonPayload(5, Guid.Empty, TreeChangeTypes.Remove), // remove middle @@ -944,14 +672,14 @@ public void RemoveTest() documents = snapshot.Content.GetAtRoot().ToArray(); AssertDocuments(documents, "N1", "N2"); - documents = snapshot.Content.GetById(1).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(1).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N4", "N6"); - documents = snapshot.Content.GetById(2).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(2).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N8", "N7"); // notify - _snapshotService.Notify(new[] + SnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(1, Guid.Empty, TreeChangeTypes.Remove), // remove first new ContentCacheRefresher.JsonPayload(8, Guid.Empty, TreeChangeTypes.Remove), // remove @@ -961,19 +689,19 @@ public void RemoveTest() documents = snapshot.Content.GetAtRoot().ToArray(); AssertDocuments(documents, "N2"); - documents = snapshot.Content.GetById(2).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(2).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents); } [Test] public void UpdateTest() { - Init(GetInvariantKits); + InitializedCache(GetInvariantKits(), _contentTypes); - var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - _snapshotAccessor.PublishedSnapshot = snapshot; + // get snapshot + var snapshot = GetPublishedSnapshot(); - var snapshotService = (PublishedSnapshotService)_snapshotService; + var snapshotService = (PublishedSnapshotService)SnapshotService; var contentStore = snapshotService.GetContentStore(); var parentNodes = contentStore.Test.GetValues(1); @@ -984,14 +712,14 @@ public void UpdateTest() var documents = snapshot.Content.GetAtRoot().ToArray(); AssertDocuments(documents, "N1", "N2", "N3"); - documents = snapshot.Content.GetById(1).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(1).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N4", "N5", "N6"); - documents = snapshot.Content.GetById(2).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(2).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N9", "N8", "N7"); // notify - _snapshotService.Notify(new[] + SnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(1, Guid.Empty, TreeChangeTypes.RefreshBranch), new ContentCacheRefresher.JsonPayload(2, Guid.Empty, TreeChangeTypes.RefreshNode), @@ -1009,10 +737,10 @@ public void UpdateTest() documents = snapshot.Content.GetAtRoot().ToArray(); AssertDocuments(documents, "N1", "N2", "N3"); - documents = snapshot.Content.GetById(1).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(1).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N4", "N5", "N6"); - documents = snapshot.Content.GetById(2).Children(_variationAccesor).ToArray(); + documents = snapshot.Content.GetById(2).Children(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N9", "N8", "N7"); @@ -1021,12 +749,12 @@ public void UpdateTest() [Test] public void AtRootTest() { - Init(GetVariantWithDraftKits); + InitializedCache(GetVariantWithDraftKits(), _contentTypes); - var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - _snapshotAccessor.PublishedSnapshot = snapshot; + // get snapshot + var snapshot = GetPublishedSnapshot(); - _variationAccesor.VariationContext = new VariationContext("en-US"); + VariationContextAccessor.VariationContext = new VariationContext("en-US"); // N2 is draft only @@ -1050,16 +778,16 @@ IEnumerable GetKits() yield return CreateInvariantKit(2, 1, 1, paths); } - Init(GetKits); + InitializedCache(GetKits(), _contentTypes); - var snapshotService = (PublishedSnapshotService)_snapshotService; + var snapshotService = (PublishedSnapshotService)SnapshotService; var contentStore = snapshotService.GetContentStore(); var parentNodes = contentStore.Test.GetValues(1); var parentNode = parentNodes[0]; AssertLinkedNode(parentNode.contentNode, -1, -1, -1, 2, 2); - _snapshotService.Notify(new[] + SnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(2, Guid.Empty, TreeChangeTypes.Remove) }, out _, out _); @@ -1089,9 +817,9 @@ IEnumerable GetKits() yield return CreateInvariantKit(4, 1, 3, paths); } - Init(GetKits); + InitializedCache(GetKits(), _contentTypes); - var snapshotService = (PublishedSnapshotService)_snapshotService; + var snapshotService = (PublishedSnapshotService)SnapshotService; var contentStore = snapshotService.GetContentStore(); Assert.AreEqual(1, contentStore.Test.LiveGen); @@ -1118,7 +846,7 @@ IEnumerable GetKits() Assert.IsFalse(contentStore.Test.NextGen); - _snapshotService.Notify(new[] + SnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(3, Guid.Empty, TreeChangeTypes.Remove) //remove middle child }, out _, out _); @@ -1169,9 +897,9 @@ IEnumerable GetKits() yield return CreateInvariantKit(40, 1, 3, paths); } - Init(GetKits); + InitializedCache(GetKits(), _contentTypes); - var snapshotService = (PublishedSnapshotService)_snapshotService; + var snapshotService = (PublishedSnapshotService)SnapshotService; var contentStore = snapshotService.GetContentStore(); Assert.AreEqual(1, contentStore.Test.LiveGen); @@ -1186,7 +914,7 @@ IEnumerable GetKits() Assert.IsFalse(contentStore.Test.NextGen); - _snapshotService.Notify(new[] + SnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(1, Guid.Empty, TreeChangeTypes.RefreshNode) }, out _, out _); @@ -1241,12 +969,12 @@ IEnumerable GetKits() } //init with all published - Init(GetKits); + InitializedCache(GetKits(), _contentTypes); - var snapshotService = (PublishedSnapshotService)_snapshotService; + var snapshotService = (PublishedSnapshotService)SnapshotService; var contentStore = snapshotService.GetContentStore(); - var rootKit = _source.Kits[1].Clone(PublishedModelFactory); + var rootKit = NuCacheContentService.ContentKits[1].Clone(PublishedModelFactory); void ChangePublishFlagOfRoot(bool published, int assertGen, TreeChangeTypes changeType) { @@ -1256,12 +984,13 @@ void ChangePublishFlagOfRoot(bool published, int assertGen, TreeChangeTypes chan Assert.IsFalse(contentStore.Test.NextGen); //Change the root publish flag - var kit = rootKit.Clone(PublishedModelFactory); - kit.DraftData = published ? null : kit.PublishedData; - kit.PublishedData = published ? kit.PublishedData : null; - _source.Kits[1] = kit; + var kit = rootKit.Clone( + PublishedModelFactory, + published ? null : rootKit.PublishedData, + published ? rootKit.PublishedData : null); + NuCacheContentService.ContentKits[1] = kit; - _snapshotService.Notify(new[] + SnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(1, Guid.Empty, changeType) }, out _, out _); @@ -1311,9 +1040,9 @@ IEnumerable GetKits() yield return CreateInvariantKit(4, 1, 3, paths); } - Init(GetKits); + InitializedCache(GetKits(), _contentTypes); - var snapshotService = (PublishedSnapshotService)_snapshotService; + var snapshotService = (PublishedSnapshotService)SnapshotService; var contentStore = snapshotService.GetContentStore(); Assert.AreEqual(1, contentStore.Test.LiveGen); @@ -1340,7 +1069,7 @@ IEnumerable GetKits() Assert.IsFalse(contentStore.Test.NextGen); - _snapshotService.Notify(new[] + SnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(3, Guid.Empty, TreeChangeTypes.RefreshBranch) //remove middle child }, out _, out _); @@ -1371,13 +1100,13 @@ IEnumerable GetKits() public void MultipleCacheIteration() { //see https://github.com/umbraco/Umbraco-CMS/issues/7798 - Init(GetInvariantKits); - var snapshot = this._snapshotService.CreatePublishedSnapshot(previewToken: null); - _snapshotAccessor.PublishedSnapshot = snapshot; + InitializedCache(GetInvariantKits(), _contentTypes); + var snapshot = GetPublishedSnapshot(); var items = snapshot.Content.GetByXPath("/root/itype"); Assert.AreEqual(items.Count(), items.Count()); } + private void AssertLinkedNode(ContentNode node, int parent, int prevSibling, int nextSibling, int firstChild, int lastChild) { Assert.AreEqual(parent, node.ParentContentId); @@ -1398,7 +1127,7 @@ private void AssertDocuments(string culture, IPublishedContent[] documents, para { Assert.AreEqual(names.Length, documents.Length); for (var i = 0; i < names.Length; i++) - Assert.AreEqual(names[i], documents[i].Name(_variationAccesor, culture)); + Assert.AreEqual(names[i], documents[i].Name(VariationContextAccessor, culture)); } } } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedSnapshotServiceContentTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedSnapshotServiceContentTests.cs new file mode 100644 index 000000000000..00c3e965c6d2 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedSnapshotServiceContentTests.cs @@ -0,0 +1,198 @@ +using System; +using System.Collections.Generic; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PublishedCache; +using Umbraco.Cms.Core.Services.Changes; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; +using Umbraco.Cms.Tests.Common.Builders; +using Umbraco.Cms.Tests.Common.Builders.Extensions; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache +{ + + + [TestFixture] + public class PublishedSnapshotServiceContentTests : PublishedSnapshotServiceTestBase + { + private ContentType _contentType; + private PropertyType _propertyType; + + [SetUp] + public override void Setup() + { + base.Setup(); + + _propertyType = new PropertyType(TestHelper.ShortStringHelper, "Umbraco.Void.Editor", ValueStorageType.Nvarchar) { Alias = "prop", DataTypeId = 3, Variations = ContentVariation.Culture }; + _contentType = new ContentType(TestHelper.ShortStringHelper, -1) { Id = 2, Alias = "alias-ct", Variations = ContentVariation.Culture }; + _contentType.AddPropertyType(_propertyType); + + var contentTypes = new[] + { + _contentType + }; + + InitializedCache(new[] { CreateKit() }, contentTypes); + } + + private ContentNodeKit CreateKit() + { + var draftData = new ContentDataBuilder() + .WithName("It Works2!") + .WithPublished(false) + .WithProperties(new Dictionary + { + ["prop"] = new[] + { + new PropertyData { Culture = "", Segment = "", Value = "val2" }, + new PropertyData { Culture = "fr-FR", Segment = "", Value = "val-fr2" }, + new PropertyData { Culture = "en-UK", Segment = "", Value = "val-uk2" }, + new PropertyData { Culture = "dk-DA", Segment = "", Value = "val-da2" }, + new PropertyData { Culture = "de-DE", Segment = "", Value = "val-de2" } + } + }) + .WithCultureInfos(new Dictionary + { + // draft data = everything, and IsDraft indicates what's edited + ["fr-FR"] = new CultureVariation { Name = "name-fr2", IsDraft = true, Date = new DateTime(2018, 01, 03, 01, 00, 00) }, + ["en-UK"] = new CultureVariation { Name = "name-uk2", IsDraft = true, Date = new DateTime(2018, 01, 04, 01, 00, 00) }, + ["dk-DA"] = new CultureVariation { Name = "name-da2", IsDraft = true, Date = new DateTime(2018, 01, 05, 01, 00, 00) }, + ["de-DE"] = new CultureVariation { Name = "name-de1", IsDraft = false, Date = new DateTime(2018, 01, 02, 01, 00, 00) } + }) + .Build(); + + var publishedData = new ContentDataBuilder() + .WithName("It Works1!") + .WithPublished(true) + .WithProperties(new Dictionary + { + ["prop"] = new[] + { + new PropertyData { Culture = "", Segment = "", Value = "val1" }, + new PropertyData { Culture = "fr-FR", Segment = "", Value = "val-fr1" }, + new PropertyData { Culture = "en-UK", Segment = "", Value = "val-uk1" } + } + }) + .WithCultureInfos(new Dictionary + { + // published data = only what's actually published, and IsDraft has to be false + ["fr-FR"] = new CultureVariation { Name = "name-fr1", IsDraft = false, Date = new DateTime(2018, 01, 01, 01, 00, 00) }, + ["en-UK"] = new CultureVariation { Name = "name-uk1", IsDraft = false, Date = new DateTime(2018, 01, 02, 01, 00, 00) }, + ["de-DE"] = new CultureVariation { Name = "name-de1", IsDraft = false, Date = new DateTime(2018, 01, 02, 01, 00, 00) } + }) + .Build(); + + var kit = ContentNodeKitBuilder.CreateWithContent( + 2, + 1, "-1,1", 0, + draftData: draftData, + publishedData: publishedData); + + return kit; + } + + [Test] + public void Verifies_Variant_Data() + { + // this test implements a full standalone NuCache (based upon a test IDataSource, does not + // use any local db files, does not rely on any database) - and tests variations + + // get a snapshot, get a published content + IPublishedSnapshot snapshot = GetPublishedSnapshot(); + IPublishedContent publishedContent = snapshot.Content.GetById(1); + + Assert.IsNotNull(publishedContent); + Assert.AreEqual("val1", publishedContent.Value(Mock.Of(), "prop")); + Assert.AreEqual("val-fr1", publishedContent.Value(Mock.Of(), "prop", "fr-FR")); + Assert.AreEqual("val-uk1", publishedContent.Value(Mock.Of(), "prop", "en-UK")); + + Assert.IsNull(publishedContent.Name(VariationContextAccessor)); // no invariant name for varying content + Assert.AreEqual("name-fr1", publishedContent.Name(VariationContextAccessor, "fr-FR")); + Assert.AreEqual("name-uk1", publishedContent.Name(VariationContextAccessor, "en-UK")); + + var draftContent = snapshot.Content.GetById(true, 1); + Assert.AreEqual("val2", draftContent.Value(Mock.Of(), "prop")); + Assert.AreEqual("val-fr2", draftContent.Value(Mock.Of(), "prop", "fr-FR")); + Assert.AreEqual("val-uk2", draftContent.Value(Mock.Of(), "prop", "en-UK")); + + Assert.IsNull(draftContent.Name(VariationContextAccessor)); // no invariant name for varying content + Assert.AreEqual("name-fr2", draftContent.Name(VariationContextAccessor, "fr-FR")); + Assert.AreEqual("name-uk2", draftContent.Name(VariationContextAccessor, "en-UK")); + + // now french is default + VariationContextAccessor.VariationContext = new VariationContext("fr-FR"); + Assert.AreEqual("val-fr1", publishedContent.Value(Mock.Of(), "prop")); + Assert.AreEqual("name-fr1", publishedContent.Name(VariationContextAccessor)); + Assert.AreEqual(new DateTime(2018, 01, 01, 01, 00, 00), publishedContent.CultureDate(VariationContextAccessor)); + + // now uk is default + VariationContextAccessor.VariationContext = new VariationContext("en-UK"); + Assert.AreEqual("val-uk1", publishedContent.Value(Mock.Of(), "prop")); + Assert.AreEqual("name-uk1", publishedContent.Name(VariationContextAccessor)); + Assert.AreEqual(new DateTime(2018, 01, 02, 01, 00, 00), publishedContent.CultureDate(VariationContextAccessor)); + + // invariant needs to be retrieved explicitly, when it's not default + Assert.AreEqual("val1", publishedContent.Value(Mock.Of(), "prop", culture: "")); + + // but, + // if the content type / property type does not vary, then it's all invariant again + // modify the content type and property type, notify the snapshot service + _contentType.Variations = ContentVariation.Nothing; + _propertyType.Variations = ContentVariation.Nothing; + SnapshotService.Notify(new[] { new ContentTypeCacheRefresher.JsonPayload("IContentType", publishedContent.ContentType.Id, ContentTypeChangeTypes.RefreshMain) }); + + // get a new snapshot (nothing changed in the old one), get the published content again + var anotherSnapshot = SnapshotService.CreatePublishedSnapshot(previewToken: null); + var againContent = anotherSnapshot.Content.GetById(1); + + Assert.AreEqual(ContentVariation.Nothing, againContent.ContentType.Variations); + Assert.AreEqual(ContentVariation.Nothing, againContent.ContentType.GetPropertyType("prop").Variations); + + // now, "no culture" means "invariant" + Assert.AreEqual("It Works1!", againContent.Name(VariationContextAccessor)); + Assert.AreEqual("val1", againContent.Value(Mock.Of(), "prop")); + } + + [Test] + public void Verifies_Published_And_Draft_Content() + { + // get the published published content + var snapshot = GetPublishedSnapshot(); + var c1 = snapshot.Content.GetById(1); + + // published content = nothing is draft here + Assert.IsFalse(c1.IsDraft("fr-FR")); + Assert.IsFalse(c1.IsDraft("en-UK")); + Assert.IsFalse(c1.IsDraft("dk-DA")); + Assert.IsFalse(c1.IsDraft("de-DE")); + + // and only those with published name, are published + Assert.IsTrue(c1.IsPublished("fr-FR")); + Assert.IsTrue(c1.IsPublished("en-UK")); + Assert.IsFalse(c1.IsDraft("dk-DA")); + Assert.IsTrue(c1.IsPublished("de-DE")); + + // get the draft published content + var c2 = snapshot.Content.GetById(true, 1); + + // draft content = we have drafts + Assert.IsTrue(c2.IsDraft("fr-FR")); + Assert.IsTrue(c2.IsDraft("en-UK")); + Assert.IsTrue(c2.IsDraft("dk-DA")); + Assert.IsFalse(c2.IsDraft("de-DE")); // except for the one that does not + + // and only those with published name, are published + Assert.IsTrue(c2.IsPublished("fr-FR")); + Assert.IsTrue(c2.IsPublished("en-UK")); + Assert.IsFalse(c2.IsPublished("dk-DA")); + Assert.IsTrue(c2.IsPublished("de-DE")); + } + + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/RootNodeTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/RootNodeTests.cs new file mode 100644 index 000000000000..1ec48759ad95 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/RootNodeTests.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache +{ + + [TestFixture] + public class RootNodeTests : PublishedSnapshotServiceTestBase + { + [SetUp] + public override void Setup() + { + base.Setup(); + + string xml = PublishedContentXml.TestWithDatabaseXml(1234); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes); + } + + [Test] + public void PublishedContentHasNoRootNode() + { + var snapshot = GetPublishedSnapshot(); + + // there is no content node with ID -1 + var content = snapshot.Content.GetById(-1); + Assert.IsNull(content); + + // content at root has null parent + content = snapshot.Content.GetById(1046); + Assert.IsNotNull(content); + Assert.AreEqual(1, content.Level); + Assert.IsNull(content.Parent); + + // non-existing content is null + content = snapshot.Content.GetById(666); + Assert.IsNull(content); + } + + } +} diff --git a/tests/Umbraco.Tests/Routing/UrlRoutesTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/UrlRoutesTests.cs similarity index 68% rename from tests/Umbraco.Tests/Routing/UrlRoutesTests.cs rename to tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/UrlRoutesTests.cs index d315cc53a52b..a2cfe7d0e63f 100644 --- a/tests/Umbraco.Tests/Routing/UrlRoutesTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/UrlRoutesTests.cs @@ -1,25 +1,23 @@ -using System; +using System; +using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.TestHelpers; +using Umbraco.Cms.Infrastructure.PublishedCache; +using Umbraco.Cms.Tests.Common.Published; +using Umbraco.Cms.Tests.UnitTests.TestHelpers; -namespace Umbraco.Tests.Routing +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.PublishedCache { // purpose: test the values returned by PublishedContentCache.GetRouteById // and .GetByRoute (no caching at all, just routing nice URLs) including all // the quirks due to hideTopLevelFromPath and backward compatibility. - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class UrlRoutesTests : TestWithDatabaseBase + public class UrlRoutesTests : PublishedSnapshotServiceTestBase { - #region Test Setup - - protected override string GetXmlContent(int templateId) - { - return @" + private static string GetXmlContent(int templateId) + => @" @@ -48,17 +46,6 @@ protected override string GetXmlContent(int templateId) "; - } - - protected override void Initialize() - { - base.Initialize(); - - if (FirstTestInFixture) - ServiceContext.ContentTypeService.Save(new ContentType(ShortStringHelper, -1) { Alias = "Doc", Name = "name" }); - } - - #endregion /* * Just so it's documented somewhere, as of jan. 2017, routes obey the following pseudo-code: @@ -193,11 +180,19 @@ compose path from parts [TestCase(2006, false, "/x/b/e")] public void GetRouteByIdNoHide(int id, bool hide, string expected) { - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = hide }; + GlobalSettings.HideTopLevelNodeFromPath = hide; - var umbracoContext = GetUmbracoContext("/test", 0, globalSettings: globalSettings); - var cache = umbracoContext.Content as PublishedContentCache; - if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); + string xml = GetXmlContent(1234); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + + var cache = GetPublishedSnapshot().Content; var route = cache.GetRouteById(false, id); Assert.AreEqual(expected, route); @@ -216,12 +211,19 @@ public void GetRouteByIdNoHide(int id, bool hide, string expected) [TestCase(2006, true, "/b/e")] // risky! public void GetRouteByIdHide(int id, bool hide, string expected) { - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = hide }; + GlobalSettings.HideTopLevelNodeFromPath = hide; + + string xml = GetXmlContent(1234); - var snapshotService = CreatePublishedSnapshotService(globalSettings); - var umbracoContext = GetUmbracoContext("/test", 0, globalSettings: globalSettings, snapshotService: snapshotService); - var cache = umbracoContext.Content as PublishedContentCache; - if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + + var cache = GetPublishedSnapshot().Content; var route = cache.GetRouteById(false, id); Assert.AreEqual(expected, route); @@ -230,27 +232,23 @@ public void GetRouteByIdHide(int id, bool hide, string expected) [Test] public void GetRouteByIdCache() { - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; + GlobalSettings.HideTopLevelNodeFromPath = false; - var snapshotService = CreatePublishedSnapshotService(globalSettings); - var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings, snapshotService: snapshotService); - var cache = umbracoContext.Content as PublishedContentCache; - if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); + string xml = GetXmlContent(1234); - var route = cache.GetRouteById(false, 1000); - Assert.AreEqual("/a", route); + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); - // GetRouteById registers a non-trusted route, which is cached for - // id -> route queries (fast GetUrl) but *not* for route -> id - // queries (safe inbound routing) + InitializedCache(kits, contentTypes, dataTypes: dataTypes); - var cachedRoutes = cache.RoutesCache.GetCachedRoutes(); - Assert.AreEqual(1, cachedRoutes.Count); - Assert.IsTrue(cachedRoutes.ContainsKey(1000)); - Assert.AreEqual("/a", cachedRoutes[1000]); + var cache = GetPublishedSnapshot().Content; - var cachedIds = cache.RoutesCache.GetCachedIds(); - Assert.AreEqual(0, cachedIds.Count); + + var route = cache.GetRouteById(false, 1000); + Assert.AreEqual("/a", route); } [TestCase("/", false, 1000)] @@ -261,12 +259,19 @@ public void GetRouteByIdCache() [TestCase("/x", false, 2000)] public void GetByRouteNoHide(string route, bool hide, int expected) { - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = hide }; + GlobalSettings.HideTopLevelNodeFromPath = hide; + + string xml = GetXmlContent(1234); - var snapshotService = CreatePublishedSnapshotService(globalSettings); - var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings, snapshotService: snapshotService); - var cache = umbracoContext.Content as PublishedContentCache; - if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); + + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + + var cache = GetPublishedSnapshot().Content; const bool preview = false; // make sure we don't cache - but HOW? should be some sort of switch?! var content = cache.GetByRoute(preview, route); @@ -292,12 +297,19 @@ public void GetByRouteNoHide(string route, bool hide, int expected) [TestCase("/b/c", true, 1002)] // (hence the 2005 collision) public void GetByRouteHide(string route, bool hide, int expected) { - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = hide }; + GlobalSettings.HideTopLevelNodeFromPath = hide; + + string xml = GetXmlContent(1234); + + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); - var snapshotService = CreatePublishedSnapshotService(globalSettings); - var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings, snapshotService: snapshotService); - var cache = umbracoContext.Content as PublishedContentCache; - if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); + InitializedCache(kits, contentTypes, dataTypes: dataTypes); + + var cache = GetPublishedSnapshot().Content; const bool preview = false; // make sure we don't cache - but HOW? should be some sort of switch?! var content = cache.GetByRoute(preview, route); @@ -315,30 +327,23 @@ public void GetByRouteHide(string route, bool hide, int expected) [Test] public void GetByRouteCache() { - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; + GlobalSettings.HideTopLevelNodeFromPath = false; - var snapshotService = CreatePublishedSnapshotService(globalSettings); - var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings, snapshotService:snapshotService); - var cache = umbracoContext.Content as PublishedContentCache; - if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); + string xml = GetXmlContent(1234); - var content = cache.GetByRoute(false, "/a/b/c"); - Assert.IsNotNull(content); - Assert.AreEqual(1002, content.Id); + IEnumerable kits = PublishedContentXmlAdapter.GetContentNodeKits( + xml, + TestHelper.ShortStringHelper, + out ContentType[] contentTypes, + out DataType[] dataTypes).ToList(); - // GetByRoute registers a trusted route, which is cached both for - // id -> route queries (fast GetUrl) and for route -> id queries - // (fast inbound routing) + InitializedCache(kits, contentTypes, dataTypes: dataTypes); - var cachedRoutes = cache.RoutesCache.GetCachedRoutes(); - Assert.AreEqual(1, cachedRoutes.Count); - Assert.IsTrue(cachedRoutes.ContainsKey(1002)); - Assert.AreEqual("/a/b/c", cachedRoutes[1002]); + var cache = GetPublishedSnapshot().Content; - var cachedIds = cache.RoutesCache.GetCachedIds(); - Assert.AreEqual(1, cachedIds.Count); - Assert.IsTrue(cachedIds.ContainsKey("/a/b/c")); - Assert.AreEqual(1002, cachedIds["/a/b/c"]); + var content = cache.GetByRoute(false, "/a/b/c"); + Assert.IsNotNull(content); + Assert.AreEqual(1002, content.Id); } } } diff --git a/tests/Umbraco.Tests/Serialization/AutoInterningStringConverterTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Serialization/AutoInterningStringConverterTests.cs similarity index 87% rename from tests/Umbraco.Tests/Serialization/AutoInterningStringConverterTests.cs rename to tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Serialization/AutoInterningStringConverterTests.cs index f83ea940c99c..472536351b05 100644 --- a/tests/Umbraco.Tests/Serialization/AutoInterningStringConverterTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Serialization/AutoInterningStringConverterTests.cs @@ -1,14 +1,11 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; using NUnit.Framework; using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Serialization; -using Umbraco.Core.Serialization; +using Umbraco.Cms.Infrastructure.Serialization; -namespace Umbraco.Tests.Serialization +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Serialization { [TestFixture] public class AutoInterningStringConverterTests @@ -61,7 +58,7 @@ public class Test public string Name { get; set; } [JsonConverter(typeof(AutoInterningStringKeyCaseInsensitiveDictionaryConverter))] - public Dictionary Values = new Dictionary(); + public Dictionary Values { get; set; } = new Dictionary(); } } } diff --git a/tests/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs b/tests/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs deleted file mode 100644 index bec5bbbb92a8..000000000000 --- a/tests/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs +++ /dev/null @@ -1,133 +0,0 @@ -using System.Linq; -using System.Xml; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Tests.Common; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.TestHelpers; -using Umbraco.Web; - -namespace Umbraco.Tests.Cache.PublishedCache -{ - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class PublishContentCacheTests : BaseWebTest - { - private FakeHttpContextFactory _httpContextFactory; - private IUmbracoContext _umbracoContext; - private IPublishedContentCache _cache; - private XmlDocument _xml; - - private string GetXml() - { - return @" - - -]> - - - - - - - - - - - - - - -"; - } - - protected override void Initialize() - { - base.Initialize(); - - _httpContextFactory = new FakeHttpContextFactory("~/Home"); - - var globalSettings = new GlobalSettings(); - var umbracoContextAccessor = Factory.GetRequiredService(); - - _xml = new XmlDocument(); - _xml.LoadXml(GetXml()); - var xmlStore = new XmlStore(() => _xml, null, null, null, HostingEnvironment); - var appCache = new DictionaryAppCache(); - var domainCache = new DomainCache(Mock.Of(), DefaultCultureAccessor); - var publishedShapshot = new PublishedSnapshot( - new PublishedContentCache(xmlStore, domainCache, appCache, globalSettings, ContentTypesCache, null, VariationContextAccessor, null), - new PublishedMediaCache(xmlStore, Mock.Of(), Mock.Of(), appCache, ContentTypesCache, Factory.GetRequiredService(), umbracoContextAccessor, VariationContextAccessor), - new PublishedMemberCache(ContentTypesCache, VariationContextAccessor), - domainCache); - var publishedSnapshotService = new Mock(); - publishedSnapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(publishedShapshot); - - var httpContext = _httpContextFactory.HttpContext; - var httpContextAccessor = TestHelper.GetHttpContextAccessor(httpContext); - _umbracoContext = new UmbracoContext( - httpContextAccessor, - publishedSnapshotService.Object, - Mock.Of(), - globalSettings, - HostingEnvironment, - new TestVariationContextAccessor(), - UriUtility, - new AspNetCookieManager(httpContextAccessor)); - - _cache = _umbracoContext.Content; - } - - [Test] - public void Has_Content() - { - Assert.IsTrue(_cache.HasContent()); - } - - - [Test] - public void Get_Root_Docs() - { - var result = _cache.GetAtRoot(); - Assert.AreEqual(2, result.Count()); - Assert.AreEqual(1046, result.ElementAt(0).Id); - Assert.AreEqual(1172, result.ElementAt(1).Id); - } - - - [TestCase("/", 1046)] - [TestCase("/home", 1046)] - [TestCase("/Home", 1046)] //test different cases - [TestCase("/home/sub1", 1173)] - [TestCase("/Home/sub1", 1173)] - [TestCase("/home/Sub1", 1173)] //test different cases - [TestCase("/home/Sub'Apostrophe", 1177)] - public void Get_Node_By_Route(string route, int nodeId) - { - var result = _cache.GetByRoute(route, false); - Assert.IsNotNull(result); - Assert.AreEqual(nodeId, result.Id); - } - - - - [TestCase("/", 1046)] - [TestCase("/sub1", 1173)] - [TestCase("/Sub1", 1173)] - public void Get_Node_By_Route_Hiding_Top_Level_Nodes(string route, int nodeId) - { - var result = _cache.GetByRoute(route, true); - Assert.IsNotNull(result); - Assert.AreEqual(nodeId, result.Id); - } - } -} diff --git a/tests/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs b/tests/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs deleted file mode 100644 index 416035e0e49a..000000000000 --- a/tests/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs +++ /dev/null @@ -1,413 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml; -using Examine; -using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.Membership; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Extensions; -using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.PublishedContent; -using Umbraco.Tests.TestHelpers; -using Constants = Umbraco.Cms.Core.Constants; -using Current = Umbraco.Web.Composing.Current; - -namespace Umbraco.Tests.Cache.PublishedCache -{ - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class PublishMediaCacheTests : BaseWebTest - { - private Dictionary _mediaTypes; - private int _testWriterAndCreatorId; - - private IUmbracoContextAccessor _umbracoContextAccessor; - protected override void Compose() - { - base.Compose(); - - Builder.WithCollectionBuilder() - .Clear() - .Append(); - - _umbracoContextAccessor = Current.UmbracoContextAccessor; - } - - protected override void Initialize() - { - base.Initialize(); - var type = new AutoPublishedContentType(Guid.NewGuid(), 22, "myType", new PublishedPropertyType[] { }); - var image = new AutoPublishedContentType(Guid.NewGuid(), 23, "Image", new PublishedPropertyType[] { }); - var testMediaType = new AutoPublishedContentType(Guid.NewGuid(), 24, "TestMediaType", new PublishedPropertyType[] { }); - _mediaTypes = new Dictionary - { - { type.Alias, type }, - { image.Alias, image }, - { testMediaType.Alias, testMediaType } - }; - ContentTypesCache.GetPublishedContentTypeByAlias = alias => _mediaTypes[alias]; - - _testWriterAndCreatorId = ServiceContext.UserService.CreateUserWithIdentity("Shannon", "test").Id; - } - - private IMediaType MakeNewMediaType(IUser user, string text, int parentId = -1) - { - var mt = new MediaType(ShortStringHelper, parentId) { Name = text, Alias = text, Thumbnail = "icon-folder", Icon = "icon-folder" }; - ServiceContext.MediaTypeService.Save(mt); - return mt; - } - - private IMedia MakeNewMedia(string name, IMediaType mediaType, IUser user, int parentId) - { - var m = ServiceContext.MediaService.CreateMediaWithIdentity(name, parentId, mediaType.Alias); - return m; - } - - //NOTE: This is "Without_Examine" too - [Test] - public void Get_Root_Docs() - { - var user = ServiceContext.UserService.GetUserById(0); - var mType = MakeNewMediaType(user, "TestMediaType"); - var mRoot1 = MakeNewMedia("MediaRoot1", mType, user, -1); - var mRoot2 = MakeNewMedia("MediaRoot2", mType, user, -1); - var mChild1 = MakeNewMedia("Child1", mType, user, mRoot1.Id); - var mChild2 = MakeNewMedia("Child2", mType, user, mRoot2.Id); - - var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument) null, null, null, null, HostingEnvironment), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetRequiredService(), Factory.GetRequiredService(), VariationContextAccessor); - var roots = cache.GetAtRoot(); - Assert.AreEqual(2, roots.Count()); - Assert.IsTrue(roots.Select(x => x.Id).ContainsAll(new[] {mRoot1.Id, mRoot2.Id})); - - } - - [Test] - public void Get_Item_Without_Examine() - { - var user = ServiceContext.UserService.GetUserById(0); - var mType = MakeNewMediaType(user, "TestMediaType"); - _mediaTypes[mType.Alias] = new PublishedContentType(mType, null); - var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); - var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); - - //var publishedMedia = PublishedMediaTests.GetNode(mRoot.Id, GetUmbracoContext("/test", 1234)); - var umbracoContext = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null, HostingEnvironment), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetRequiredService(), Factory.GetRequiredService(), VariationContextAccessor); - var publishedMedia = cache.GetById(mRoot.Id); - Assert.IsNotNull(publishedMedia); - - Assert.AreEqual(mRoot.Id, publishedMedia.Id); - Assert.AreEqual(mRoot.CreateDate.ToString("dd/MM/yyyy HH:mm:ss"), publishedMedia.CreateDate.ToString("dd/MM/yyyy HH:mm:ss")); - Assert.AreEqual(mRoot.CreatorId, publishedMedia.CreatorId); - //Assert.AreEqual(mRoot.User.Name, publishedMedia.CreatorName); - Assert.AreEqual(mRoot.ContentType.Alias, publishedMedia.ContentType.Alias); - Assert.AreEqual(mRoot.ContentType.Id, publishedMedia.ContentType.Id); - Assert.AreEqual(mRoot.Level, publishedMedia.Level); - Assert.AreEqual(mRoot.Name, publishedMedia.Name); - Assert.AreEqual(mRoot.Path, publishedMedia.Path); - Assert.AreEqual(mRoot.SortOrder, publishedMedia.SortOrder); - Assert.IsNull(publishedMedia.Parent); - } - - [TestCase("id")] - [TestCase("__NodeId")] - public void DictionaryDocument_Id_Keys(string key) - { - var dicDoc = GetDictionaryDocument(idKey: key); - DoAssert(dicDoc); - } - - [TestCase("template")] - [TestCase("templateId")] - public void DictionaryDocument_Template_Keys(string key) - { - var dicDoc = GetDictionaryDocument(templateKey: key); - DoAssert(dicDoc); - } - - [TestCase("nodeName")] - public void DictionaryDocument_NodeName_Keys(string key) - { - var dicDoc = GetDictionaryDocument(nodeNameKey: key); - DoAssert(dicDoc); - } - - [TestCase("nodeTypeAlias")] - [TestCase("__NodeTypeAlias")] - public void DictionaryDocument_NodeTypeAlias_Keys(string key) - { - var dicDoc = GetDictionaryDocument(nodeTypeAliasKey: key); - DoAssert(dicDoc); - } - - [TestCase("path")] - [TestCase("__Path")] - public void DictionaryDocument_Path_Keys(string key) - { - var dicDoc = GetDictionaryDocument(pathKey: key); - DoAssert(dicDoc); - } - - [Test] - public void DictionaryDocument_Key() - { - var key = Guid.NewGuid(); - var dicDoc = GetDictionaryDocument(keyVal: key); - DoAssert(dicDoc, keyVal: key); - } - - [Test] - public void DictionaryDocument_Get_Children() - { - var child1 = GetDictionaryDocument(idVal: 222333); - var child2 = GetDictionaryDocument(idVal: 444555); - - var dicDoc = GetDictionaryDocument(children: new List() - { - child1, child2 - }); - - Assert.AreEqual(2, dicDoc.Children.Count()); - Assert.AreEqual(222333, dicDoc.Children.ElementAt(0).Id); - Assert.AreEqual(444555, dicDoc.Children.ElementAt(1).Id); - } - - [Test] - public void Convert_From_Search_Result() - { - var ctx = GetUmbracoContext("/test"); - var key = Guid.NewGuid(); - - var fields = new Dictionary - { - {"__IndexType", "media"}, - {"__NodeId", "1234"}, - {"__NodeTypeAlias", Constants.Conventions.MediaTypes.Image}, - {"__Path", "-1,1234"}, - {"__nodeName", "Test"}, - {"id", "1234"}, - {"key", key.ToString()}, - {"urlName", "/media/test.jpg"}, - {"nodeType", "0"}, - {"sortOrder", "0"}, - {"level", "2"}, - {"nodeName", "Test"}, - {"nodeTypeAlias", Constants.Conventions.MediaTypes.Image}, - {"parentID", "-1"}, - {"path", "-1,1234"}, - {"updateDate", DateTime.Parse("2012-07-16T10:34:09").Ticks.ToString()}, - {"createDate", DateTime.Parse("2012-07-17T10:34:09").Ticks.ToString()}, - {"creatorID", _testWriterAndCreatorId.ToString()}, - {"creatorName", "Shannon"} - }; - - var result = new SearchResult("1234", 1, () => fields.ToDictionary(x => x.Key, x => new List { x.Value })); - - var store = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null, HostingEnvironment), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetRequiredService(), Factory.GetRequiredService(), VariationContextAccessor); - var doc = store.CreateFromCacheValues(store.ConvertFromSearchResult(result)); - - DoAssert(doc, 1234, key, null, 0, "/media/test.jpg", "Image", 23, "Shannon", "Shannon", "-1,1234", DateTime.Parse("2012-07-17T10:34:09"), DateTime.Parse("2012-07-16T10:34:09"), 2); - Assert.AreEqual(null, doc.Parent); - } - - [Test] - public void Convert_From_XPath_Navigator() - { - var ctx = GetUmbracoContext("/test"); - var key = Guid.NewGuid(); - - var xmlDoc = GetMediaXml(); - ((XmlElement)xmlDoc.DocumentElement.FirstChild).SetAttribute("key", key.ToString()); - var navigator = xmlDoc.SelectSingleNode("/root/Image").CreateNavigator(); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null, HostingEnvironment), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetRequiredService(), Factory.GetRequiredService(),VariationContextAccessor); - var doc = cache.CreateFromCacheValues(cache.ConvertFromXPathNavigator(navigator, true)); - - DoAssert(doc, 2000, key, null, 2, "image1", "Image", 23, "Shannon", "Shannon", "-1,2000", DateTime.Parse("2012-06-12T14:13:17"), DateTime.Parse("2012-07-20T18:50:43"), 1); - Assert.AreEqual(null, doc.Parent); - Assert.AreEqual(2, doc.Children.Count()); - Assert.AreEqual(2001, doc.Children.ElementAt(0).Id); - Assert.AreEqual(2002, doc.Children.ElementAt(1).Id); - } - - private XmlDocument GetMediaXml() - { - var xml = @" - - - - -]> - - - - - - - - - - -"; - xml = xml.Replace("[WriterId]", _testWriterAndCreatorId.ToString()); - xml = xml.Replace("[CreatorId]", _testWriterAndCreatorId.ToString()); - - var xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(xml); - return xmlDoc; - } - - private Dictionary GetDictionary( - int id, - Guid key, - int parentId, - string idKey, - string templateKey, - string nodeNameKey, - string nodeTypeAliasKey, - string pathKey) - { - return new Dictionary() - { - {idKey, id.ToString()}, - {"key", key.ToString()}, - {templateKey, "0"}, - {"sortOrder", "44"}, - {nodeNameKey, "Testing"}, - {"urlName", "testing"}, - {nodeTypeAliasKey, "myType"}, - {"nodeType", "22"}, - {"writerID", _testWriterAndCreatorId.ToString()}, - {"creatorID", _testWriterAndCreatorId.ToString()}, - {pathKey, "1,2,3,4,5"}, - {"createDate", "2012-01-02"}, - {"updateDate", "2012-01-02"}, - {"level", "3"}, - {"parentID", parentId.ToString()} - }; - } - - private DictionaryPublishedContent GetDictionaryDocument( - string idKey = "id", - string templateKey = "template", - string nodeNameKey = "nodeName", - string nodeTypeAliasKey = "nodeTypeAlias", - string pathKey = "path", - int idVal = 1234, - Guid keyVal = default(Guid), - int parentIdVal = 321, - IEnumerable children = null) - { - if (children == null) - children = new List(); - var dicDoc = new DictionaryPublishedContent( - //the dictionary - GetDictionary(idVal, keyVal, parentIdVal, idKey, templateKey, nodeNameKey, nodeTypeAliasKey, pathKey), - //callback to get the parent - d => new DictionaryPublishedContent( - // the dictionary - GetDictionary(parentIdVal, default(Guid), -1, idKey, templateKey, nodeNameKey, nodeTypeAliasKey, pathKey), - // callback to get the parent: there is no parent - a => null, - // callback to get the children: we're not going to test this so ignore - (dd, n) => new List(), - // callback to get a property - (dd, a) => dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(a)), - null, // cache provider - VariationContextAccessor, - ContentTypesCache, - // no xpath - null, - // not from examine - false), - //callback to get the children - (dd, n) => children, - // callback to get a property - (dd, a) => dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(a)), - null, // cache provider - VariationContextAccessor, - ContentTypesCache, - // no xpath - null, - // not from examine - false); - return dicDoc; - } - - private void DoAssert( - DictionaryPublishedContent dicDoc, - int idVal = 1234, - Guid keyVal = default(Guid), - int? templateIdVal = null, - int sortOrderVal = 44, - string urlNameVal = "testing", - string nodeTypeAliasVal = "myType", - int nodeTypeIdVal = 22, - string writerNameVal = "Shannon", - string creatorNameVal = "Shannon", - string pathVal = "1,2,3,4,5", - DateTime? createDateVal = null, - DateTime? updateDateVal = null, - int levelVal = 3, - int parentIdVal = 321) - { - if (!createDateVal.HasValue) - createDateVal = DateTime.Parse("2012-01-02"); - if (!updateDateVal.HasValue) - updateDateVal = DateTime.Parse("2012-01-02"); - - DoAssert((IPublishedContent)dicDoc, idVal, keyVal, templateIdVal, sortOrderVal, urlNameVal, nodeTypeAliasVal, nodeTypeIdVal, writerNameVal, - creatorNameVal, pathVal, createDateVal, updateDateVal, levelVal); - - //now validate the parentId that has been parsed, this doesn't exist on the IPublishedContent - Assert.AreEqual(parentIdVal, dicDoc.ParentId); - } - - private void DoAssert( - IPublishedContent doc, - int idVal = 1234, - Guid keyVal = default(Guid), - int? templateIdVal = null, - int sortOrderVal = 44, - string urlNameVal = "testing", - string nodeTypeAliasVal = "myType", - int nodeTypeIdVal = 22, - string writerNameVal = "Shannon", - string creatorNameVal = "Shannon", - string pathVal = "1,2,3,4,5", - DateTime? createDateVal = null, - DateTime? updateDateVal = null, - int levelVal = 3) - { - if (!createDateVal.HasValue) - createDateVal = DateTime.Parse("2012-01-02"); - if (!updateDateVal.HasValue) - updateDateVal = DateTime.Parse("2012-01-02"); - - Assert.AreEqual(idVal, doc.Id); - Assert.AreEqual(keyVal, doc.Key); - Assert.AreEqual(templateIdVal, doc.TemplateId); - Assert.AreEqual(sortOrderVal, doc.SortOrder); - Assert.AreEqual(urlNameVal, doc.UrlSegment); - Assert.AreEqual(nodeTypeAliasVal, doc.ContentType.Alias); - Assert.AreEqual(nodeTypeIdVal, doc.ContentType.Id); - Assert.AreEqual(writerNameVal, doc.GetWriterName(ServiceContext.UserService)); - Assert.AreEqual(creatorNameVal, doc.GetCreatorName(ServiceContext.UserService)); - Assert.AreEqual(_testWriterAndCreatorId, doc.WriterId); - Assert.AreEqual(_testWriterAndCreatorId, doc.CreatorId); - Assert.AreEqual(pathVal, doc.Path); - Assert.AreEqual(createDateVal.Value, doc.CreateDate); - Assert.AreEqual(updateDateVal.Value, doc.UpdateDate); - Assert.AreEqual(levelVal, doc.Level); - } - } -} diff --git a/tests/Umbraco.Tests/Issues/U9560.cs b/tests/Umbraco.Tests/Issues/U9560.cs deleted file mode 100644 index 8687e6e07cf8..000000000000 --- a/tests/Umbraco.Tests/Issues/U9560.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests.Issues -{ - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true)] - public class U9560 : TestWithDatabaseBase - { - [Test] - public void Test() - { - // create a content type and some properties - var contentType = new ContentType(ShortStringHelper, -1); - contentType.Alias = "test"; - contentType.Name = "test"; - var propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "prop") { Name = "Prop", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; - contentType.PropertyTypeCollection.Add(propertyType); - ServiceContext.ContentTypeService.Save(contentType); - - var aliasName = string.Empty; - - // read fields, same as what we do with PetaPoco Fetch - using (var db = Factory.GetRequiredService().CreateDatabase()) - { - db.OpenSharedConnection(); - try - { - var conn = db.Connection; - var cmd = conn.CreateCommand(); - cmd.CommandText = "SELECT mandatory, dataTypeId, propertyTypeGroupId, contentTypeId, sortOrder, alias, name, validationRegExp, description from cmsPropertyType where id=" + propertyType.Id; - using (var reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - for (var i = 0; i < reader.FieldCount; i++) - Console.WriteLine(reader.GetName(i)); - aliasName = reader.GetName(5); - } - } - } - finally - { - db.CloseSharedConnection(); - } - } - - // note that although the query is for 'alias' the field is named 'Alias' - Assert.AreEqual("Alias", aliasName); - - // try differently - using (var db = Factory.GetRequiredService().CreateDatabase()) - { - db.OpenSharedConnection(); - try - { - var conn = db.Connection; - var cmd = conn.CreateCommand(); - cmd.CommandText = "SELECT mandatory, dataTypeId, propertyTypeGroupId, contentTypeId, sortOrder, alias as alias, name, validationRegExp, description from cmsPropertyType where id=" + propertyType.Id; - using (var reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - for (var i = 0; i < reader.FieldCount; i++) - Console.WriteLine(reader.GetName(i)); - aliasName = reader.GetName(5); - } - } - } - finally - { - db.CloseSharedConnection(); - } - } - - // and now it is OK - Assert.AreEqual("alias", aliasName); - - //// get the legacy content type - //var legacyContentType = new umbraco.cms.businesslogic.ContentType(contentType.Id); - //Assert.AreEqual("test", legacyContentType.Alias); - - //// get the legacy properties - //var legacyProperties = legacyContentType.PropertyTypes; - - //// without the fix, due to some (swallowed) inner exception, we have no properties - ////Assert.IsNull(legacyProperties); - - //// thanks to the fix, it works - //Assert.IsNotNull(legacyProperties); - //Assert.AreEqual(1, legacyProperties.Count); - //Assert.AreEqual("prop", legacyProperties[0].Alias); - } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/ContentXmlDto.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/ContentXmlDto.cs deleted file mode 100644 index d7d82bdd6d33..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/ContentXmlDto.cs +++ /dev/null @@ -1,24 +0,0 @@ -using NPoco; -using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations; -using Umbraco.Cms.Infrastructure.Persistence.Dtos; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - [TableName("cmsContentXml")] - [PrimaryKey("nodeId", AutoIncrement = false)] - [ExplicitColumns] - internal class ContentXmlDto - { - [Column("nodeId")] - [PrimaryKeyColumn(AutoIncrement = false)] - [ForeignKey(typeof(ContentDto), Column = "nodeId")] - public int NodeId { get; set; } - - [Column("xml")] - [SpecialDbType(SpecialDbTypes.NTEXT)] - public string Xml { get; set; } - - [Column("rv")] - public long Rv { get; set; } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/DictionaryPublishedContent.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/DictionaryPublishedContent.cs deleted file mode 100644 index b6f886574815..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/DictionaryPublishedContent.cs +++ /dev/null @@ -1,221 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Xml.XPath; -using Examine; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Extensions; -using Umbraco.Web.Composing; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - /// - /// An IPublishedContent that is represented all by a dictionary. - /// - /// - /// This is a helper class and definitely not intended for public use, it expects that all of the values required - /// to create an IPublishedContent exist in the dictionary by specific aliases. - /// - internal class DictionaryPublishedContent : PublishedContentBase - { - // note: I'm not sure this class fully complies with IPublishedContent rules especially - // I'm not sure that _properties contains all properties including those without a value, - // neither that GetProperty will return a property without a value vs. null... @zpqrtbnk - - // List of properties that will appear in the XML and do not match - // anything in the ContentType, so they must be ignored. - private static readonly string[] IgnoredKeys = { "version", "isDoc" }; - - public DictionaryPublishedContent( - IReadOnlyDictionary valueDictionary, - Func getParent, - Func> getChildren, - Func getProperty, - IAppCache appCache, - IVariationContextAccessor variationContextAccessor, - PublishedContentTypeCache contentTypeCache, - XPathNavigator nav, - bool fromExamine):base(variationContextAccessor) - { - if (valueDictionary == null) throw new ArgumentNullException(nameof(valueDictionary)); - if (getParent == null) throw new ArgumentNullException(nameof(getParent)); - if (getProperty == null) throw new ArgumentNullException(nameof(getProperty)); - - _getParent = new Lazy(() => getParent(ParentId)); - _getChildren = new Lazy>(() => getChildren(Id, nav)); - _getProperty = getProperty; - _appCache = appCache; - - LoadedFromExamine = fromExamine; - - ValidateAndSetProperty(valueDictionary, val => _id = Int32.Parse(val), "id", "nodeId", "__NodeId"); //should validate the int! - ValidateAndSetProperty(valueDictionary, val => _key = Guid.Parse(val), "key", "__key", "__Key"); - //ValidateAndSetProperty(valueDictionary, val => _templateId = int.Parse(val), "template", "templateId"); - ValidateAndSetProperty(valueDictionary, val => _sortOrder = Int32.Parse(val), "sortOrder"); - ValidateAndSetProperty(valueDictionary, val => _name = val, "nodeName"); - ValidateAndSetProperty(valueDictionary, val => _urlName = val, "urlName"); - ValidateAndSetProperty(valueDictionary, val => _documentTypeAlias = val, "nodeTypeAlias", ExamineFieldNames.ItemTypeFieldName); - ValidateAndSetProperty(valueDictionary, val => _documentTypeId = Int32.Parse(val), "nodeType"); - //ValidateAndSetProperty(valueDictionary, val => _writerId = int.Parse(val), "writerID"); - ValidateAndSetProperty(valueDictionary, val => _creatorId = Int32.Parse(val), "creatorID", "writerID"); //this is a bit of a hack fix for: U4-1132 - ValidateAndSetProperty(valueDictionary, val => _path = val, "path", "__Path"); - ValidateAndSetProperty(valueDictionary, val => _createDate = ParseDateTimeValue(val), "createDate"); - ValidateAndSetProperty(valueDictionary, val => _updateDate = ParseDateTimeValue(val), "updateDate"); - ValidateAndSetProperty(valueDictionary, val => _level = Int32.Parse(val), "level"); - ValidateAndSetProperty(valueDictionary, val => - { - int pId; - ParentId = -1; - if (Int32.TryParse(val, out pId)) - { - ParentId = pId; - } - }, "parentID"); - - _contentType = contentTypeCache.Get(PublishedItemType.Media, _documentTypeAlias); - _properties = new Collection(); - - //handle content type properties - //make sure we create them even if there's no value - foreach (var propertyType in _contentType.PropertyTypes) - { - var alias = propertyType.Alias; - _keysAdded.Add(alias); - string value; - const bool isPreviewing = false; // false :: never preview a media - var property = valueDictionary.TryGetValue(alias, out value) == false || value == null - ? new XmlPublishedProperty(propertyType, this, isPreviewing) - : new XmlPublishedProperty(propertyType, this, isPreviewing, value); - _properties.Add(property); - } - - //loop through remaining values that haven't been applied - foreach (var i in valueDictionary.Where(x => - _keysAdded.Contains(x.Key) == false // not already processed - && IgnoredKeys.Contains(x.Key) == false)) // not ignorable - { - if (i.Key.InvariantStartsWith("__")) - { - // no type for that one, dunno how to convert, drop it - //IPublishedProperty property = new PropertyResult(i.Key, i.Value, PropertyResultType.CustomProperty); - //_properties.Add(property); - } - else - { - // this is a property that does not correspond to anything, ignore and log - Current.Logger.LogWarning("Dropping property '{PropertyKey}' because it does not belong to the content type.", i.Key); - } - } - } - - private DateTime ParseDateTimeValue(string val) - { - if (LoadedFromExamine == false) - return DateTime.Parse(val); - - //we need to parse the date time using Lucene converters - var ticks = Int64.Parse(val); - return new DateTime(ticks); - } - - /// - /// Flag to get/set if this was loaded from examine cache - /// - internal bool LoadedFromExamine { get; } - - //private readonly Func _getParent; - private readonly Lazy _getParent; - //private readonly Func> _getChildren; - private readonly Lazy> _getChildren; - private readonly Func _getProperty; - private readonly IAppCache _appCache; - - /// - /// Returns 'Media' as the item type - /// - public override PublishedItemType ItemType => PublishedItemType.Media; - - public override IPublishedContent Parent => _getParent.Value; - - public int ParentId { get; private set; } - - public override int Id => _id; - - public override Guid Key => _key; - - public override int? TemplateId => null; - - public override int SortOrder => _sortOrder; - - public override string Name => _name; - - private static readonly Lazy> NoCultures = new Lazy>(() => new Dictionary()); - public override IReadOnlyDictionary Cultures => NoCultures.Value; - - public override string UrlSegment => _urlName; - - public override int WriterId => _creatorId; - - public override int CreatorId => _creatorId; - - public override string Path => _path; - - public override DateTime CreateDate => _createDate; - - public override DateTime UpdateDate => _updateDate; - - public override int Level => _level; - - public override bool IsDraft(string culture = null) => false; - - public override bool IsPublished(string culture = null) => true; - - public override IEnumerable Properties => _properties; - - public override IEnumerable Children => _getChildren.Value; - - public override IEnumerable ChildrenForAllCultures => Children; - - public override IPublishedProperty GetProperty(string alias) - { - return _getProperty(this, alias); - } - - public override IPublishedContentType ContentType => _contentType; - - private readonly List _keysAdded = new List(); - private int _id; - private Guid _key; - //private int _templateId; - private int _sortOrder; - private string _name; - private string _urlName; - private string _documentTypeAlias; - private int _documentTypeId; - //private int _writerId; - private int _creatorId; - private string _path; - private DateTime _createDate; - private DateTime _updateDate; - //private Guid _version; - private int _level; - private readonly ICollection _properties; - private readonly IPublishedContentType _contentType; - - private void ValidateAndSetProperty(IReadOnlyDictionary valueDictionary, Action setProperty, params string[] potentialKeys) - { - var key = potentialKeys.FirstOrDefault(x => valueDictionary.ContainsKey(x) && valueDictionary[x] != null); - if (key == null) - { - throw new FormatException("The valueDictionary is not formatted correctly and is missing any of the '" + String.Join(",", potentialKeys) + "' elements"); - } - - setProperty(valueDictionary[key]); - _keysAdded.Add(key); - } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/DomainCache.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/DomainCache.cs deleted file mode 100644 index 0ff61e7e45d4..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/DomainCache.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Services; -using Umbraco.Extensions; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - internal class DomainCache : IDomainCache - { - private readonly IDomainService _domainService; - - public DomainCache(IDomainService domainService, IDefaultCultureAccessor defaultCultureAccessor) - { - _domainService = domainService; - DefaultCulture = defaultCultureAccessor.DefaultCulture; - } - - /// - public IEnumerable GetAll(bool includeWildcards) => _domainService.GetAll(includeWildcards) - .Where(x => x.RootContentId.HasValue && x.LanguageIsoCode.IsNullOrWhiteSpace() == false) - .Select(x => new Domain(x.Id, x.DomainName, x.RootContentId.Value, x.LanguageIsoCode, x.IsWildcard)); - - /// - public IEnumerable GetAssigned(int documentId, bool includeWildcards = false) => _domainService.GetAssignedDomains(documentId, includeWildcards) - .Where(x => x.RootContentId.HasValue && x.LanguageIsoCode.IsNullOrWhiteSpace() == false) - .Select(x => new Domain(x.Id, x.DomainName, x.RootContentId.Value, x.LanguageIsoCode, x.IsWildcard)); - - /// - public bool HasAssigned(int documentId, bool includeWildcards = false) - => documentId > 0 && GetAssigned(documentId, includeWildcards).Any(); - - /// - public string DefaultCulture { get; } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/BackgroundTaskRunner.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/BackgroundTaskRunner.cs deleted file mode 100644 index 98aa1cf8d8fe..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/BackgroundTaskRunner.cs +++ /dev/null @@ -1,863 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using System.Threading.Tasks.Dataflow; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.Runtime; - -namespace Umbraco.Web.Scheduling -{ - /// - /// Manages a queue of tasks and runs them in the background. - /// - /// This class exists for logging purposes - the one you want to use is BackgroundTaskRunner{T}. - public abstract class BackgroundTaskRunner - { - /// - /// Represents a MainDom hook. - /// - public class MainDomHook - { - /// - /// Initializes a new instance of the class. - /// - /// The object. - /// A method to execute when hooking into the main domain. - /// A method to execute when the main domain releases. - public MainDomHook(IMainDom mainDom, Action install, Action release) - { - MainDom = mainDom; - Install = install; - Release = release; - } - - /// - /// Gets the object. - /// - public IMainDom MainDom { get; } - - /// - /// Gets the method to execute when hooking into the main domain. - /// - public Action Install { get; } - - /// - /// Gets the method to execute when the main domain releases. - /// - public Action Release { get; } - - internal bool Register() - { - if (MainDom != null) - { - return MainDom.Register(Install, Release); - } - - // tests - Install?.Invoke(); - return true; - } - } - } - - /// - /// Manages a queue of tasks of type and runs them in the background. - /// - /// The type of the managed tasks. - /// The task runner is web-aware and will ensure that it shuts down correctly when the AppDomain - /// shuts down (ie is unloaded). - public class BackgroundTaskRunner : BackgroundTaskRunner, IBackgroundTaskRunner - where T : class, IBackgroundTask - { - // do not remove this comment! - // - // if you plan to do anything on this class, first go and read - // http://blog.stephencleary.com/2012/12/dont-block-in-asynchronous-code.html - // http://stackoverflow.com/questions/19481964/calling-taskcompletionsource-setresult-in-a-non-blocking-manner - // http://stackoverflow.com/questions/21225361/is-there-anything-like-asynchronous-blockingcollectiont - // and more, and more, and more - // and remember: async is hard - - private readonly string _logPrefix; - private readonly BackgroundTaskRunnerOptions _options; - private readonly ILogger> _logger; - private readonly IApplicationShutdownRegistry _applicationShutdownRegistry; - private readonly object _locker = new object(); - - private readonly BufferBlock _tasks = new BufferBlock(new DataflowBlockOptions()); - - // in various places we are testing these vars outside a lock, so make them volatile - private volatile bool _isRunning; // is running - private volatile bool _completed; // does not accept tasks anymore, may still be running - - private Task _runningTask; // the threading task that is currently executing background tasks - private CancellationTokenSource _shutdownTokenSource; // used to cancel everything and shutdown - private CancellationTokenSource _cancelTokenSource; // used to cancel the current task - private CancellationToken _shutdownToken; - - private bool _terminating; // ensures we raise that event only once - private bool _terminated; // remember we've terminated - private readonly TaskCompletionSource _terminatedSource = new TaskCompletionSource(); // enable awaiting termination - - /// - /// Initializes a new instance of the class. - /// - /// A logger. - /// The application shutdown registry - /// An optional main domain hook. - public BackgroundTaskRunner(ILogger> logger, IApplicationShutdownRegistry applicationShutdownRegistry, MainDomHook hook = null) - : this(typeof(T).FullName, new BackgroundTaskRunnerOptions(), logger, applicationShutdownRegistry, hook) - { } - - /// - /// Initializes a new instance of the class. - /// - /// The name of the runner. - /// A logger. - /// The application shutdown registry - /// An optional main domain hook. - public BackgroundTaskRunner(string name, ILogger> logger, IApplicationShutdownRegistry applicationShutdownRegistry, MainDomHook hook = null) - : this(name, new BackgroundTaskRunnerOptions(), logger, applicationShutdownRegistry, hook) - { } - - /// - /// Initializes a new instance of the class with a set of options. - /// - /// The set of options. - /// A logger. - /// The application shutdown registry - /// An optional main domain hook. - public BackgroundTaskRunner(BackgroundTaskRunnerOptions options, ILogger> logger, IApplicationShutdownRegistry applicationShutdownRegistry, MainDomHook hook = null) - : this(typeof(T).FullName, options, logger, applicationShutdownRegistry, hook) - { } - - /// - /// Initializes a new instance of the class with a set of options. - /// - /// The name of the runner. - /// The set of options. - /// A logger. - /// The application shutdown registry - /// An optional main domain hook. - public BackgroundTaskRunner(string name, BackgroundTaskRunnerOptions options, ILogger> logger, IApplicationShutdownRegistry applicationShutdownRegistry, MainDomHook hook = null) - { - _options = options ?? throw new ArgumentNullException(nameof(options)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _applicationShutdownRegistry = applicationShutdownRegistry; - _logPrefix = "[" + name + "] "; - - if (options.Hosted) - _applicationShutdownRegistry.RegisterObject(this); - - if (hook != null) - _completed = _terminated = hook.Register() == false; - - if (options.AutoStart && _terminated == false) - StartUp(); - } - - /// - /// Gets the number of tasks in the queue. - /// - public int TaskCount => _tasks.Count; - - /// - /// Gets a value indicating whether a threading task is currently running. - /// - public bool IsRunning => _isRunning; - - /// - /// Gets a value indicating whether the runner has completed and cannot accept tasks anymore. - /// - public bool IsCompleted => _completed; - - /// - /// Gets the running threading task as an immutable awaitable. - /// - /// There is no running task. - /// - /// Unless the AutoStart option is true, there will be no current threading task until - /// a background task is added to the queue, and there will be no current threading task - /// when the queue is empty. In which case this method returns null. - /// The returned value can be awaited and that is all (eg no continuation). - /// - internal ThreadingTaskImmutable CurrentThreadingTask - { - get - { - lock (_locker) - { - return _runningTask == null ? null : new ThreadingTaskImmutable(_runningTask); - } - } - } - - /// - /// Gets an awaitable used to await the runner running operation. - /// - /// An awaitable instance. - /// Used to wait until the runner is no longer running (IsRunning == false), - /// though the runner could be started again afterwards by adding tasks to it. If - /// the runner is not running, returns a completed awaitable. - public ThreadingTaskImmutable StoppedAwaitable - { - get - { - lock (_locker) - { - var task = _runningTask ?? Task.CompletedTask; - return new ThreadingTaskImmutable(task); - } - } - } - - /// - /// Gets an awaitable object that can be used to await for the runner to terminate. - /// - /// An awaitable object. - /// - /// Used to wait until the runner has terminated. - /// - /// The only time the runner will be terminated is by the Hosting Environment when the application is being shutdown. - /// - /// - internal ThreadingTaskImmutable TerminatedAwaitable - { - get - { - lock (_locker) - { - return new ThreadingTaskImmutable(_terminatedSource.Task); - } - } - } - - /// - /// Adds a task to the queue. - /// - /// The task to add. - /// The task runner has completed. - public void Add(T task) - { - lock (_locker) - { - if (_completed) - throw new InvalidOperationException("The task runner has completed."); - - // add task - _logger.LogDebug("{LogPrefix} Task Added {TaskType}", _logPrefix , task.GetType().FullName); - _tasks.Post(task); - - // start - StartUpLocked(); - } - } - - /// - /// Tries to add a task to the queue. - /// - /// The task to add. - /// true if the task could be added to the queue; otherwise false. - /// Returns false if the runner is completed. - public bool TryAdd(T task) - { - lock (_locker) - { - if (_completed) - { - _logger.LogDebug("{LogPrefix} Task cannot be added {TaskType}, the task runner has already shutdown", _logPrefix, task.GetType().FullName); - return false; - } - - // add task - _logger.LogDebug("{LogPrefix} Task added {TaskType}", _logPrefix, task.GetType().FullName); - _tasks.Post(task); - - // start - StartUpLocked(); - - return true; - } - } - - /// - /// Cancels to current task, if any. - /// - /// Has no effect if the task runs synchronously, or does not want to cancel. - public void CancelCurrentBackgroundTask() - { - lock (_locker) - { - if (_completed) - throw new InvalidOperationException("The task runner has completed."); - _cancelTokenSource?.Cancel(); - } - } - - /// - /// Starts the tasks runner, if not already running. - /// - /// Is invoked each time a task is added, to ensure it is going to be processed. - /// The task runner has completed. - internal void StartUp() - { - if (_isRunning) return; - - lock (_locker) - { - if (_completed) - throw new InvalidOperationException("The task runner has completed."); - - StartUpLocked(); - } - } - - /// - /// Starts the tasks runner, if not already running. - /// - /// Must be invoked within lock(_locker) and with _isCompleted being false. - private void StartUpLocked() - { - // double check - if (_isRunning) return; - _isRunning = true; - - // create a new token source since this is a new process - _shutdownTokenSource = new CancellationTokenSource(); - _shutdownToken = _shutdownTokenSource.Token; - using (ExecutionContext.SuppressFlow()) // Do not flow AsyncLocal to the child thread - { - _runningTask = Task.Run(async () => await Pump().ConfigureAwait(false), _shutdownToken); - } - - _logger.LogDebug("{LogPrefix} Starting", _logPrefix); - } - - /// - /// Shuts the tasks runner down. - /// - /// True for force the runner to stop. - /// True to wait until the runner has stopped. - /// If is false, no more tasks can be queued but all queued tasks - /// will run. If it is true, then only the current one (if any) will end and no other task will run. - public void Shutdown(bool force, bool wait) - { - lock (_locker) - { - _completed = true; // do not accept new tasks - if (_isRunning == false) return; // done already - } - - var hasTasks = TaskCount > 0; - - if (!force && hasTasks) - { - _logger.LogInformation("{LogPrefix} Waiting for tasks to complete", _logPrefix); - } - - // complete the queue - // will stop waiting on the queue or on a latch - _tasks.Complete(); - - if (force) - { - // we must bring everything down, now - lock (_locker) - { - // was Complete() enough? - // if _tasks.Complete() ended up triggering code to stop the runner and reset - // the _isRunning flag, then there's no need to initiate a cancel on the cancelation token. - if (_isRunning == false) - return; - } - - // try to cancel running async tasks (cannot do much about sync tasks) - // break latched tasks - // stop processing the queue - _shutdownTokenSource?.Cancel(false); // false is the default - _shutdownTokenSource?.Dispose(); - _shutdownTokenSource = null; - } - - // tasks in the queue will be executed... - if (!wait) return; - - _runningTask?.Wait(CancellationToken.None); // wait for whatever is running to end... - } - - private async Task Pump() - { - while (true) - { - // get the next task - // if it returns null the runner is going down, stop - var bgTask = await GetNextBackgroundTask(_shutdownToken); - if (bgTask == null) return; - - // set a cancellation source so that the current task can be cancelled - // link from _shutdownToken so that we can use _cancelTokenSource for both - lock (_locker) - { - _cancelTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_shutdownToken); - } - - try - { - // wait for latch should return the task - // if it returns null it's either that the task has been cancelled - // or the whole runner is going down - in both cases, continue, - // and GetNextBackgroundTask will take care of shutdowns - bgTask = await WaitForLatch(bgTask, _cancelTokenSource.Token); - - if (bgTask != null) - { - // executes & be safe - RunAsync should NOT throw but only raise an event, - // but... just make sure we never ever take everything down - try - { - await RunAsync(bgTask, _cancelTokenSource.Token).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogError(ex, "{LogPrefix} Task runner exception", _logPrefix); - } - } - } - finally - { - // done - lock (_locker) - { - // always dispose CancellationTokenSource when you are done using them - // https://lowleveldesign.org/2015/11/30/catch-in-cancellationtokensource/ - _cancelTokenSource.Dispose(); - _cancelTokenSource = null; - } - } - } - } - - // gets the next background task from the buffer - private async Task GetNextBackgroundTask(CancellationToken token) - { - while (true) - { - var task = await GetNextBackgroundTask2(token); - if (task != null) return task; - - lock (_locker) - { - // deal with race condition - if (_shutdownToken.IsCancellationRequested == false && TaskCount > 0) continue; - - // if we really have nothing to do, stop - _logger.LogDebug("{LogPrefix} Stopping", _logPrefix); - - if (_options.PreserveRunningTask == false) - _runningTask = null; - _isRunning = false; - _shutdownToken = CancellationToken.None; - } - - OnEvent(Stopped, "Stopped"); - return null; - } - } - - private async Task GetNextBackgroundTask2(CancellationToken shutdownToken) - { - // exit if canceling - if (shutdownToken.IsCancellationRequested) - return null; - - // if KeepAlive is false then don't block, exit if there is - // no task in the buffer - yes, there is a race condition, which - // we'll take care of - if (_options.KeepAlive == false && TaskCount == 0) - return null; - - try - { - // A Task that informs of whether and when more output is available. If, when the - // task completes, its Result is true, more output is available in the source (though another - // consumer of the source may retrieve the data). If it returns false, more output is not - // and will never be available, due to the source completing prior to output being available. - - var output = await _tasks.OutputAvailableAsync(shutdownToken); // block until output or cancelled - if (output == false) return null; - } - catch (TaskCanceledException) - { - return null; - } - - try - { - // A task that represents the asynchronous receive operation. When an item value is successfully - // received from the source, the returned task is completed and its Result returns the received - // value. If an item value cannot be retrieved because the source is empty and completed, an - // InvalidOperationException exception is thrown in the returned task. - - // the source cannot be empty *and* completed here - we know we have output - return await _tasks.ReceiveAsync(shutdownToken); - } - catch (TaskCanceledException) - { - return null; - } - } - - // if bgTask is not a latched background task, or if it is not latched, returns immediately - // else waits for the latch, taking care of completion and shutdown and whatnot - private async Task WaitForLatch(T bgTask, CancellationToken token) - { - var latched = bgTask as ILatchedBackgroundTask; - if (latched == null || latched.IsLatched == false) return bgTask; - - // support canceling awaiting - // read https://github.com/dotnet/corefx/issues/2704 - // read http://stackoverflow.com/questions/27238232/how-can-i-cancel-task-whenall - var tokenTaskSource = new TaskCompletionSource(); - token.Register(s => ((TaskCompletionSource)s).SetResult(true), tokenTaskSource); - - // returns the task that completed - // - latched.Latch completes when the latch releases - // - _tasks.Completion completes when the runner completes - // - tokenTaskSource.Task completes when this task, or the whole runner is cancelled - var task = await Task.WhenAny(latched.Latch, _tasks.Completion, tokenTaskSource.Task); - - // ok to run now - if (task == latched.Latch) - return bgTask; - - // we are shutting down if the _tasks.Complete(); was called or the shutdown token was cancelled - var isShuttingDown = _shutdownToken.IsCancellationRequested || task == _tasks.Completion; - - // if shutting down, return the task only if it runs on shutdown - if (isShuttingDown && latched.RunsOnShutdown) - return bgTask; - - // else, either it does not run on shutdown or it's been cancelled, dispose - latched.Dispose(); - return null; - } - - // runs the background task, taking care of shutdown (as far as possible - cannot abort - // a non-async Run for example, so we'll do our best) - private async Task RunAsync(T bgTask, CancellationToken token) - { - try - { - OnTaskStarting(new TaskEventArgs(bgTask)); - - try - { - try - { - if (bgTask.IsAsync) - { - // configure await = false since we don't care about the context, we're on a background thread. - await bgTask.RunAsync(token).ConfigureAwait(false); - } - else - { - bgTask.Run(); - } - } - finally // ensure we disposed - unless latched again ie wants to re-run - { - if (!(bgTask is ILatchedBackgroundTask lbgTask) || lbgTask.IsLatched == false) - { - bgTask.Dispose(); - } - } - } - catch (Exception e) - { - OnTaskError(new TaskEventArgs(bgTask, e)); - throw; - } - - OnTaskCompleted(new TaskEventArgs(bgTask)); - } - catch (Exception ex) - { - - _logger.LogError(ex, "{LogPrefix} Task has failed", _logPrefix); - } - } - - #region Events - - // triggers when a background task starts - public event TypedEventHandler, TaskEventArgs> TaskStarting; - - // triggers when a background task has completed - public event TypedEventHandler, TaskEventArgs> TaskCompleted; - - // triggers when a background task throws - public event TypedEventHandler, TaskEventArgs> TaskError; - - // triggers when a background task is cancelled - public event TypedEventHandler, TaskEventArgs> TaskCancelled; - - // triggers when the runner stops (but could start again if a task is added to it) - internal event TypedEventHandler, EventArgs> Stopped; - - // triggers when the hosting environment requests that the runner terminates - internal event TypedEventHandler, EventArgs> Terminating; - - // triggers when the hosting environment has terminated (no task can be added, no task is running) - internal event TypedEventHandler, EventArgs> Terminated; - - private void OnEvent(TypedEventHandler, EventArgs> handler, string name) - { - OnEvent(handler, name, EventArgs.Empty); - } - - private void OnEvent(TypedEventHandler, TArgs> handler, string name, TArgs e) - { - _logger.LogDebug("{LogPrefix} OnEvent {EventName}", _logPrefix, name); - - if (handler == null) return; - - try - { - handler(this, e); - } - catch (Exception ex) - { - _logger.LogError(ex, "{LogPrefix} {Name} exception occurred", _logPrefix, name); - } - } - - protected virtual void OnTaskError(TaskEventArgs e) - { - OnEvent(TaskError, "TaskError", e); - } - - protected virtual void OnTaskStarting(TaskEventArgs e) - { - OnEvent(TaskStarting, "TaskStarting", e); - } - - protected virtual void OnTaskCompleted(TaskEventArgs e) - { - OnEvent(TaskCompleted, "TaskCompleted", e); - } - - protected virtual void OnTaskCancelled(TaskEventArgs e) - { - OnEvent(TaskCancelled, "TaskCancelled", e); - - // dispose it - e.Task.Dispose(); - } - - #endregion - - #region IDisposable - - private readonly object _disposalLocker = new object(); - public bool IsDisposed { get; private set; } - - ~BackgroundTaskRunner() - { - Dispose(false); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (IsDisposed || disposing == false) - return; - - lock (_disposalLocker) - { - if (IsDisposed) - return; - DisposeResources(); - IsDisposed = true; - } - } - - protected virtual void DisposeResources() - { - // just make sure we eventually go down - Shutdown(true, false); - } - - #endregion - - #region IRegisteredObject.Stop - - /// - /// Used by IRegisteredObject.Stop and shutdown on threadpool threads to not block shutdown times. - /// - /// - /// - /// An awaitable Task that is used to handle the shutdown. - /// - internal Task StopInternal(bool immediate) - { - // the first time the hosting environment requests that the runner terminates, - // raise the Terminating event - that could be used to prevent any process that - // would expect the runner to be available from starting. - var onTerminating = false; - lock (_locker) - { - if (_terminating == false) - { - _terminating = true; - _logger.LogInformation("{LogPrefix} Terminating {Immediate}", _logPrefix, immediate ? immediate.ToString() : string.Empty); - onTerminating = true; - } - } - - if (onTerminating) - OnEvent(Terminating, "Terminating"); - - // Run the Stop commands on another thread since IRegisteredObject.Stop calls are called sequentially - // with a single aspnet thread during shutdown and we don't want to delay other calls to IRegisteredObject.Stop. - if (!immediate) - { - using (ExecutionContext.SuppressFlow()) - { - return Task.Run(StopInitial, CancellationToken.None); - } - } - else - { - lock (_locker) - { - if (_terminated) return Task.CompletedTask; - using (ExecutionContext.SuppressFlow()) - { - return Task.Run(StopImmediate, CancellationToken.None); - } - } - } - } - - /// - /// Requests a registered object to un-register. - /// - /// true to indicate the registered object should un-register from the hosting - /// environment before returning; otherwise, false. - /// - /// "When the application manager needs to stop a registered object, it will call the Stop method." - /// The application manager will call the Stop method to ask a registered object to un-register. During - /// processing of the Stop method, the registered object must call the applicationShutdownRegistry.UnregisterObject method. - /// - public void Stop(bool immediate) => StopInternal(immediate); - - /// - /// Called when immediate == false for IRegisteredObject.Stop(bool immediate) - /// - /// - /// Called on a threadpool thread - /// - private void StopInitial() - { - // immediate == false when the app is trying to wind down, immediate == true will be called either: - // after a call with immediate == false or if the app is not trying to wind down and needs to immediately stop. - // So Stop may be called twice or sometimes only once. - - try - { - Shutdown(false, false); // do not accept any more tasks, flush the queue, do not wait - } - finally - { - // raise the completed event only after the running threading task has completed - lock (_locker) - { - if (_runningTask != null) - { - _runningTask.ContinueWith( - _ => StopImmediate(), - // Must explicitly specify this, see https://blog.stephencleary.com/2013/10/continuewith-is-dangerous-too.html - TaskScheduler.Default); - } - else - { - StopImmediate(); - } - - } - } - - // If the shutdown token was not canceled in the Shutdown call above, it means there was still tasks - // being processed, in which case we'll give it a couple seconds - if (!_shutdownToken.IsCancellationRequested) - { - // If we are called with immediate == false, wind down above and then shutdown within 2 seconds, - // we want to shut down the app as quick as possible, if we wait until immediate == true, this can - // take a very long time since immediate will only be true when a new request is received on the new - // appdomain (or another iis timeout occurs ... which can take some time). - Thread.Sleep(2000); //we are already on a threadpool thread - StopImmediate(); - } - } - - /// - /// Called when immediate == true for IRegisteredObject.Stop(bool immediate) - /// - /// - /// Called on a threadpool thread - /// - private void StopImmediate() - { - _logger.LogInformation("{LogPrefix} Canceling tasks", _logPrefix); - try - { - Shutdown(true, true); // cancel all tasks, wait for the current one to end - } - finally - { - Terminate(true); - } - } - - // called by Stop either immediately or eventually - private void Terminate(bool immediate) - { - // signal the environment we have terminated - // log - // raise the Terminated event - // complete the awaitable completion source, if any - - if (immediate) - { - //only unregister when it's the final call, else we won't be notified of the final call - _applicationShutdownRegistry.UnregisterObject(this); - } - - if (_terminated) return; // already taken care of - - TaskCompletionSource terminatedSource; - lock (_locker) - { - _terminated = true; - terminatedSource = _terminatedSource; - } - - _logger.LogInformation("{LogPrefix} Tasks {TaskStatus}, terminated", - _logPrefix, - immediate ? "cancelled" : "completed"); - - OnEvent(Terminated, "Terminated"); - - terminatedSource.TrySetResult(0); - } - - #endregion - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/BackgroundTaskRunnerOptions.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/BackgroundTaskRunnerOptions.cs deleted file mode 100644 index bc0369fee83a..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/BackgroundTaskRunnerOptions.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace Umbraco.Web.Scheduling -{ - /// - /// Provides options to the class. - /// - public class BackgroundTaskRunnerOptions - { - // TODO: Could add options for using a stack vs queue if required - - /// - /// Initializes a new instance of the class. - /// - public BackgroundTaskRunnerOptions() - { - LongRunning = false; - KeepAlive = false; - AutoStart = false; - PreserveRunningTask = false; - Hosted = true; - } - - /// - /// Gets or sets a value indicating whether the running task should be a long-running, - /// coarse grained operation. - /// - public bool LongRunning { get; set; } - - /// - /// Gets or sets a value indicating whether the running task should block and wait - /// on the queue, or end, when the queue is empty. - /// - public bool KeepAlive { get; set; } - - /// - /// Gets or sets a value indicating whether the running task should start immediately - /// or only once a task has been added to the queue. - /// - public bool AutoStart { get; set; } - - /// - /// Gets or sets a value indicating whether the running task should be preserved - /// once completed, or reset to null. For unit tests. - /// - public bool PreserveRunningTask { get; set; } - - /// - /// Gets or sets a value indicating whether the runner should register with (and be - /// stopped by) the hosting. Otherwise, something else should take care of stopping - /// the runner. True by default. - /// - public bool Hosted { get; set; } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/IBackgroundTask.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/IBackgroundTask.cs deleted file mode 100644 index b1285d0080e2..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/IBackgroundTask.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Umbraco.Web.Scheduling -{ - /// - /// Represents a background task. - /// - public interface IBackgroundTask : IDisposable - { - /// - /// Runs the background task. - /// - void Run(); - - /// - /// Runs the task asynchronously. - /// - /// A cancellation token. - /// A instance representing the execution of the background task. - /// The background task cannot run asynchronously. - Task RunAsync(CancellationToken token); - - /// - /// Indicates whether the background task can run asynchronously. - /// - bool IsAsync { get; } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/IBackgroundTaskRunner.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/IBackgroundTaskRunner.cs deleted file mode 100644 index 52dc75f3fbdb..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/IBackgroundTaskRunner.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Umbraco.Cms.Core; - -namespace Umbraco.Web.Scheduling -{ - /// - /// Defines a service managing a queue of tasks of type and running them in the background. - /// - /// The type of the managed tasks. - /// The interface is not complete and exists only to have the contravariance on T. - public interface IBackgroundTaskRunner : IDisposable, IRegisteredObject - where T : class, IBackgroundTask - { - bool IsCompleted { get; } - void Add(T task); - bool TryAdd(T task); - - // TODO: complete the interface? - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/ILatchedBackgroundTask.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/ILatchedBackgroundTask.cs deleted file mode 100644 index e981623b34c1..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/ILatchedBackgroundTask.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Umbraco.Web.Scheduling -{ - /// - /// Represents a latched background task. - /// - /// Latched background tasks can suspend their execution until - /// a condition is met. However if the tasks runner has to terminate, - /// latched background tasks can be executed immediately, depending on - /// the value returned by RunsOnShutdown. - public interface ILatchedBackgroundTask : IBackgroundTask - { - /// - /// Gets a task on latch. - /// - /// The task is not latched. - Task Latch { get; } - - /// - /// Gets a value indicating whether the task is latched. - /// - /// Should return false as soon as the condition is met. - bool IsLatched { get; } - - /// - /// Gets a value indicating whether the task can be executed immediately if the task runner has to terminate. - /// - bool RunsOnShutdown { get; } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/LatchedBackgroundTaskBase.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/LatchedBackgroundTaskBase.cs deleted file mode 100644 index 738bed9b5bdf..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/LatchedBackgroundTaskBase.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Umbraco.Cms.Core; - -namespace Umbraco.Web.Scheduling -{ - public abstract class LatchedBackgroundTaskBase : DisposableObjectSlim, ILatchedBackgroundTask - { - private TaskCompletionSource _latch; - - protected LatchedBackgroundTaskBase() - { - _latch = new TaskCompletionSource(); - } - - /// - /// Implements IBackgroundTask.Run(). - /// - public virtual void Run() - { - throw new NotSupportedException("This task cannot run synchronously."); - } - - /// - /// Implements IBackgroundTask.RunAsync(). - /// - public virtual Task RunAsync(CancellationToken token) - { - throw new NotSupportedException("This task cannot run asynchronously."); - } - - /// - /// Indicates whether the background task can run asynchronously. - /// - public abstract bool IsAsync { get; } - - public Task Latch => _latch.Task; - - public bool IsLatched => _latch.Task.IsCompleted == false; - - protected void Release() - { - _latch.SetResult(true); - } - - protected void Reset() - { - _latch = new TaskCompletionSource(); - } - - public virtual bool RunsOnShutdown => false; - - // the task is going to be disposed after execution, - // unless it is latched again, thus indicating it wants to - // remain active - - protected override void DisposeResources() - { } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/TaskEventArgs.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/TaskEventArgs.cs deleted file mode 100644 index 972bc1290151..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/TaskEventArgs.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; - -namespace Umbraco.Web.Scheduling -{ - /// - /// Provides arguments for task runner events. - /// - /// The type of the task. - public class TaskEventArgs : EventArgs - where T : IBackgroundTask - { - /// - /// Initializes a new instance of the class with a task. - /// - /// The task. - public TaskEventArgs(T task) - { - Task = task; - } - - /// - /// Initializes a new instance of the class with a task and an exception. - /// - /// The task. - /// An exception. - public TaskEventArgs(T task, Exception exception) - { - Task = task; - Exception = exception; - } - - /// - /// Gets or sets the task. - /// - public T Task { get; private set; } - - /// - /// Gets or sets the exception. - /// - public Exception Exception { get; private set; } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/ThreadingTaskImmutable.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/ThreadingTaskImmutable.cs deleted file mode 100644 index b1ea0d7f71ba..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/ThreadingTaskImmutable.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -namespace Umbraco.Web.Scheduling -{ - /// - /// Wraps a within an object that gives access to its GetAwaiter method and Status - /// property while ensuring that it cannot be modified in any way. - /// - public class ThreadingTaskImmutable - { - private readonly Task _task; - - /// - /// Initializes a new instance of the class with a Task. - /// - /// The task. - public ThreadingTaskImmutable(Task task) - { - if (task == null) - throw new ArgumentNullException("task"); - _task = task; - } - - /// - /// Gets an awaiter used to await the task. - /// - /// An awaiter instance. - public TaskAwaiter GetAwaiter() - { - return _task.GetAwaiter(); - } - - /// - /// Gets the TaskStatus of the task. - /// - /// The current TaskStatus of the task. - public TaskStatus Status - { - get { return _task.Status; } - } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/PreviewContent.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/PreviewContent.cs deleted file mode 100644 index f190b7ee41f7..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/PreviewContent.cs +++ /dev/null @@ -1,164 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Xml; -using Microsoft.Extensions.Logging; -using Umbraco.Extensions; -using Umbraco.Tests.TestHelpers; -using Umbraco.Web.Composing; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - class PreviewContent - { - private readonly int _userId; - private readonly Guid _previewSet; - private string _previewSetPath; - private XmlDocument _previewXml; - private readonly XmlStore _xmlStore; - - /// - /// Gets the XML document. - /// - /// May return null if the preview content set is invalid. - public XmlDocument XmlContent - { - get - { - // null if invalid preview content - if (_previewSetPath == null) return null; - - // load if not loaded yet - if (_previewXml != null) - return _previewXml; - - _previewXml = new XmlDocument(); - - try - { - _previewXml.Load(_previewSetPath); - } - catch (Exception ex) - { - Current.Logger.LogError(ex, "Could not load preview set {PreviewSet} for user {UserId}.", _previewSet, _userId); - - ClearPreviewSet(); - - _previewXml = null; - _previewSetPath = null; // do not try again - } - - return _previewXml; - } - } - - /// - /// Gets the preview token. - /// - /// To be stored in a cookie or wherever appropriate. - public string Token => _userId + ":" + _previewSet; - - /// - /// Initializes a new instance of the class for a user. - /// - /// The underlying Xml store. - /// The user identifier. - public PreviewContent(XmlStore xmlStore, int userId) - { - if (xmlStore == null) - throw new ArgumentNullException(nameof(xmlStore)); - _xmlStore = xmlStore; - - _userId = userId; - _previewSet = Guid.NewGuid(); - _previewSetPath = GetPreviewSetPath(_userId, _previewSet); - } - - /// - /// Initializes a new instance of the with a preview token. - /// - /// The underlying Xml store. - /// The preview token. - public PreviewContent(XmlStore xmlStore, string token) - { - if (xmlStore == null) - throw new ArgumentNullException(nameof(xmlStore)); - _xmlStore = xmlStore; - - if (token.IsNullOrWhiteSpace()) - throw new ArgumentException("Null or empty token.", nameof(token)); - var parts = token.Split(':'); - if (parts.Length != 2) - throw new ArgumentException("Invalid token.", nameof(token)); - - if (int.TryParse(parts[0], out _userId) == false) - throw new ArgumentException("Invalid token.", nameof(token)); - if (Guid.TryParse(parts[1], out _previewSet) == false) - throw new ArgumentException("Invalid token.", nameof(token)); - - _previewSetPath = GetPreviewSetPath(_userId, _previewSet); - } - - // creates and saves a new preview set - // used in 2 places and each time includeSubs is true - // have to use the Document class at the moment because IContent does not do ToXml... - public void CreatePreviewSet(int contentId, bool includeSubs) - { - // note: always include subs - _previewXml = _xmlStore.GetPreviewXml(contentId, includeSubs); - - // make sure the preview folder exists - var dir = new DirectoryInfo(TestHelper.IOHelper.MapPath(Constants.SystemDirectories.Preview)); - if (dir.Exists == false) - dir.Create(); - - // clean old preview sets - ClearPreviewDirectory(_userId, dir); - - // save - _previewXml.Save(_previewSetPath); - } - - // get the full path to the preview set - private static string GetPreviewSetPath(int userId, Guid previewSet) - { - return TestHelper.IOHelper.MapPath(Path.Combine(Constants.SystemDirectories.Preview, userId + "_" + previewSet + ".config")); - } - - // deletes files for the user, and files accessed more than one hour ago - private static void ClearPreviewDirectory(int userId, DirectoryInfo dir) - { - var now = DateTime.Now; - var prefix = userId + "_"; - foreach (var file in dir.GetFiles("*.config") - .Where(x => x.Name.StartsWith(prefix) || (now - x.LastAccessTime).TotalMinutes > 1)) - { - DeletePreviewSetFile(userId, file); - } - } - - // delete one preview set file in a safe way - private static void DeletePreviewSetFile(int userId, FileSystemInfo file) - { - try - { - file.Delete(); - } - catch (Exception ex) - { - Current.Logger.LogError(ex, "Couldn't delete preview set {FileName} for user {UserId}", file.Name, userId); - } - } - - /// - /// Deletes the preview set in a safe way. - /// - public void ClearPreviewSet() - { - if (_previewSetPath == null) return; - var previewSetFile = new FileInfo(_previewSetPath); - DeletePreviewSetFile(_userId, previewSetFile); - } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/PreviewXmlDto.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/PreviewXmlDto.cs deleted file mode 100644 index ba49167fda2b..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/PreviewXmlDto.cs +++ /dev/null @@ -1,24 +0,0 @@ -using NPoco; -using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations; -using Umbraco.Cms.Infrastructure.Persistence.Dtos; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - [TableName("cmsPreviewXml")] - [PrimaryKey("nodeId", AutoIncrement = false)] - [ExplicitColumns] - internal class PreviewXmlDto - { - [Column("nodeId")] - [PrimaryKeyColumn(AutoIncrement = false)] - [ForeignKey(typeof(ContentDto), Column = "nodeId")] - public int NodeId { get; set; } - - [Column("xml")] - [SpecialDbType(SpecialDbTypes.NTEXT)] - public string Xml { get; set; } - - [Column("rv")] - public long Rv { get; set; } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedContentCache.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedContentCache.cs deleted file mode 100644 index 6bfaa075b2d2..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedContentCache.cs +++ /dev/null @@ -1,548 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Xml; -using System.Xml.XPath; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Xml; -using Umbraco.Extensions; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - internal class PublishedContentCache : PublishedCacheBase, IPublishedContentCache - { - private readonly IAppCache _appCache; - private readonly GlobalSettings _globalSettings; - private readonly RoutesCache _routesCache; - private readonly IVariationContextAccessor _variationContextAccessor; - private readonly IDomainCache _domainCache; - private readonly PublishedContentTypeCache _contentTypeCache; - - // initialize a PublishedContentCache instance with - // an XmlStore containing the master xml - // an IAppCache that should be at request-level - // a RoutesCache - need to cleanup that one - // a preview token string (or null if not previewing) - public PublishedContentCache( - XmlStore xmlStore, // an XmlStore containing the master xml - IDomainCache domainCache, // an IDomainCache implementation - IAppCache appCache, // an IAppCache that should be at request-level - GlobalSettings globalSettings, - PublishedContentTypeCache contentTypeCache, // a PublishedContentType cache - RoutesCache routesCache, // a RoutesCache - IVariationContextAccessor variationContextAccessor, - string previewToken) // a preview token string (or null if not previewing) - : base(previewToken.IsNullOrWhiteSpace() == false) - { - _appCache = appCache; - _globalSettings = globalSettings; - _routesCache = routesCache; // may be null for unit-testing - _variationContextAccessor = variationContextAccessor; - _contentTypeCache = contentTypeCache; - _domainCache = domainCache; - - _xmlStore = xmlStore; - _xml = _xmlStore.Xml; // capture - because the cache has to remain consistent - - if (previewToken.IsNullOrWhiteSpace() == false) - _previewContent = new PreviewContent(_xmlStore, previewToken); - } - - #region Unit Tests - - // for INTERNAL, UNIT TESTS use ONLY - internal RoutesCache RoutesCache => _routesCache; - - // for INTERNAL, UNIT TESTS use ONLY - internal XmlStore XmlStore => _xmlStore; - - #endregion - - #region Routes - - public virtual IPublishedContent GetByRoute(bool preview, string route, bool? hideTopLevelNode = null, string culture = null) - { - if (route == null) throw new ArgumentNullException(nameof(route)); - - // try to get from cache if not previewing - var contentId = preview || _routesCache == null ? 0 : _routesCache.GetNodeId(route); - - // if found id in cache then get corresponding content - // and clear cache if not found - for whatever reason - IPublishedContent content = null; - if (contentId > 0) - { - content = GetById(preview, contentId); - if (content == null) - _routesCache?.ClearNode(contentId); - } - - // still have nothing? actually determine the id - hideTopLevelNode = hideTopLevelNode ?? _globalSettings.HideTopLevelNodeFromPath; // default = settings - content = content ?? DetermineIdByRoute(preview, route, hideTopLevelNode.Value); - - // cache if we have a content and not previewing - if (content != null && preview == false && _routesCache != null) - AddToCacheIfDeepestRoute(content, route); - - return content; - } - - private void AddToCacheIfDeepestRoute(IPublishedContent content, string route) - { - var domainRootNodeId = route.StartsWith("/") ? -1 : int.Parse(route.Substring(0, route.IndexOf('/'))); - - // so we have a route that maps to a content... say "1234/path/to/content" - however, there could be a - // domain set on "to" and route "4567/content" would also map to the same content - and due to how - // URLs computing work (by walking the tree up to the first domain we find) it is that second route - // that would be returned - the "deepest" route - and that is the route we want to cache, *not* the - // longer one - so make sure we don't cache the wrong route - - var deepest = DomainUtilities.ExistsDomainInPath(_domainCache.GetAll(false), content.Path, domainRootNodeId) == false; - - if (deepest) - _routesCache.Store(content.Id, route, true); // trusted route - } - - public IPublishedContent GetByRoute(string route, bool? hideTopLevelNode = null, string culture = null) - { - return GetByRoute(PreviewDefault, route, hideTopLevelNode); - } - - public virtual string GetRouteById(bool preview, int contentId, string culture = null) - { - // try to get from cache if not previewing - var route = preview || _routesCache == null ? null : _routesCache.GetRoute(contentId); - - // if found in cache then return - if (route != null) - return route; - - // else actually determine the route - route = DetermineRouteById(preview, contentId); - - // node not found - if (route == null) - return null; - - // cache the route BUT do NOT trust it as it can be a colliding route - // meaning if we GetRouteById again, we'll get it from cache, but it - // won't be used for inbound routing - if (preview == false) - _routesCache.Store(contentId, route, false); - - return route; - } - - public string GetRouteById(int contentId, string culture = null) - { - return GetRouteById(PreviewDefault, contentId, culture); - } - - IPublishedContent DetermineIdByRoute(bool preview, string route, bool hideTopLevelNode) - { - //the route always needs to be lower case because we only store the urlName attribute in lower case - route = route?.ToLowerInvariant() ?? throw new ArgumentNullException(nameof(route)); - - var pos = route.IndexOf('/'); - var path = pos == 0 ? route : route.Substring(pos); - var startNodeId = pos == 0 ? 0 : int.Parse(route.Substring(0, pos)); - - //check if we can find the node in our xml cache - var id = NavigateRoute(preview, startNodeId, path, hideTopLevelNode); - return id > 0 ? GetById(preview, id) : null; - } - - private static XmlElement GetXmlElementChildWithLowestSortOrder(XmlNode element) - { - XmlElement elt = null; - var min = int.MaxValue; - foreach (var n in element.ChildNodes) - { - var e = n as XmlElement; - if (e == null) continue; - - var sortOrder = int.Parse(e.GetAttribute("sortOrder")); - if (sortOrder >= min) continue; - - min = sortOrder; - elt = e; - } - return elt; - } - - private int NavigateRoute(bool preview, int startNodeId, string path, bool hideTopLevelNode) - { - var xml = GetXml(preview); - XmlElement elt; - - // empty path - if (path == string.Empty || path == "/") - { - if (startNodeId > 0) - { - elt = xml.GetElementById(startNodeId.ToString(CultureInfo.InvariantCulture)); - return elt == null ? -1 : startNodeId; - } - - elt = GetXmlElementChildWithLowestSortOrder(xml.DocumentElement); - return elt == null ? -1 : int.Parse(elt.GetAttribute("id")); - } - - // non-empty path - elt = startNodeId <= 0 - ? xml.DocumentElement - : xml.GetElementById(startNodeId.ToString(CultureInfo.InvariantCulture)); - if (elt == null) return -1; - - var urlParts = path.Split(SlashChar, StringSplitOptions.RemoveEmptyEntries); - - if (hideTopLevelNode && startNodeId <= 0) - { - //Don't use OfType or Cast, this is critical code, all ChildNodes are XmlElement so explicitly cast - // https://gist.github.com/Shazwazza/04e2e5642a316f4a87e52dada2901198 - foreach (var n in elt.ChildNodes) - { - var e = n as XmlElement; - if (e == null) continue; - - var id = NavigateElementRoute(e, urlParts); - if (id > 0) return id; - } - - if (urlParts.Length > 1) - return -1; - } - - return NavigateElementRoute(elt, urlParts); - } - - private static int NavigateElementRoute(XmlElement elt, string[] urlParts) - { - var found = true; - var i = 0; - while (found && i < urlParts.Length) - { - found = false; - //Don't use OfType or Cast, this is critical code, all ChildNodes are XmlElement so explicitly cast - // https://gist.github.com/Shazwazza/04e2e5642a316f4a87e52dada2901198 - var sortOrder = -1; - foreach (var o in elt.ChildNodes) - { - var child = o as XmlElement; - if (child == null) continue; - - var noNode = child.GetAttributeNode("isDoc") == null; - if (noNode) continue; - if (child.GetAttribute("urlName") != urlParts[i]) continue; - - found = true; - - var so = int.Parse(child.GetAttribute("sortOrder")); - if (sortOrder >= 0 && so >= sortOrder) continue; - - sortOrder = so; - elt = child; - } - i++; - } - return found ? int.Parse(elt.GetAttribute("id")) : -1; - } - - string DetermineRouteById(bool preview, int contentId) - { - var node = GetById(preview, contentId); - if (node == null) return null; - - // walk up from that node until we hit a node with a domain, - // or we reach the content root, collecting URLs in the way - var pathParts = new List(); - var n = node; - var hasDomains = _domainCache.HasAssigned(n.Id); - while (hasDomains == false && n != null) // n is null at root - { - // get the url - var urlName = n.UrlSegment(TestHelper.VariationContextAccessor); - pathParts.Add(urlName); - - // move to parent node - n = n.Parent; - hasDomains = n != null && _domainCache.HasAssigned(n.Id); - } - - // no domain, respect HideTopLevelNodeFromPath for legacy purposes - if (hasDomains == false && _globalSettings.HideTopLevelNodeFromPath) - { - if (node.Parent == null) - { - var rootNode = GetByRoute(preview, "/", true); - if (rootNode == null) - throw new Exception("Failed to get node at /."); - if (rootNode.Id == node.Id) // remove only if we're the default node - pathParts.RemoveAt(pathParts.Count - 1); - } - else - { - pathParts.RemoveAt(pathParts.Count - 1); - } - } - - // assemble the route - pathParts.Reverse(); - var path = "/" + string.Join("/", pathParts); // will be "/" or "/foo" or "/foo/bar" etc - var route = (n?.Id.ToString(CultureInfo.InvariantCulture) ?? "") + path; - - return route; - } - - #endregion - - #region XPath Strings - - static class XPathStrings - { - public const string Root = "/root"; - public const string RootDocuments = "/root/* [@isDoc]"; - } - - #endregion - - #region Converters - - private IPublishedContent ConvertToDocument(XmlNode xmlNode, bool isPreviewing) - { - return xmlNode == null ? null : XmlPublishedContent.Get(xmlNode, isPreviewing, _appCache, _contentTypeCache, _variationContextAccessor); - } - - private IEnumerable ConvertToDocuments(XmlNodeList xmlNodes, bool isPreviewing) - { - return xmlNodes.Cast() - .Select(xmlNode => XmlPublishedContent.Get(xmlNode, isPreviewing, _appCache, _contentTypeCache, _variationContextAccessor)); - } - - #endregion - - #region Getters - - public override IPublishedContent GetById(bool preview, int nodeId) - { - return ConvertToDocument(GetXml(preview).GetElementById(nodeId.ToString(CultureInfo.InvariantCulture)), preview); - } - - public override IPublishedContent GetById(bool preview, Guid nodeId) - { - // implement this, but in a more efficient way - //const string xpath = "//* [@isDoc and @key=$guid]"; - //return GetSingleByXPath(preview, xpath, new[] { new XPathVariable("guid", nodeId.ToString()) }); - - var keyMatch = nodeId.ToString(); - - var nav = GetXml(preview).CreateNavigator(); - if (nav.MoveToFirstChild() == false) return null; // from / to /root - if (nav.MoveToFirstChild() == false) return null; // from /root to /root/* - - while (true) - { - var isDoc = false; - string key = null; - - if (nav.HasAttributes) - { - nav.MoveToFirstAttribute(); - do - { - if (nav.Name == "isDoc") isDoc = true; - if (nav.Name == "key") key = nav.Value; - if (isDoc && key != null) break; - } while (nav.MoveToNextAttribute()); - nav.MoveToParent(); - } - - if (isDoc == false || key != keyMatch) - { - if (isDoc && nav.MoveToFirstChild()) - continue; - while (nav.MoveToNext(XPathNodeType.Element) == false) - if (nav.MoveToParent() == false || nav.NodeType == XPathNodeType.Root) return null; - continue; - } - - var elt = nav.UnderlyingObject as XmlNode; - return ConvertToDocument(elt, preview); - } - } - - public override IPublishedContent GetById(bool preview, Udi nodeId) - => throw new NotSupportedException(); - - public override bool HasById(bool preview, int contentId) - { - return GetXml(preview).CreateNavigator().MoveToId(contentId.ToString(CultureInfo.InvariantCulture)); - } - - public override IEnumerable GetAtRoot(bool preview, string culture = null) - { - return ConvertToDocuments(GetXml(preview).SelectNodes(XPathStrings.RootDocuments), preview); - } - - public override IPublishedContent GetSingleByXPath(bool preview, string xpath, XPathVariable[] vars) - { - if (xpath == null) throw new ArgumentNullException(nameof(xpath)); - if (string.IsNullOrWhiteSpace(xpath)) return null; - - var xml = GetXml(preview); - var node = vars == null - ? xml.SelectSingleNode(xpath) - : xml.SelectSingleNode(xpath, vars); - return ConvertToDocument(node, preview); - } - - public override IPublishedContent GetSingleByXPath(bool preview, XPathExpression xpath, XPathVariable[] vars) - { - if (xpath == null) throw new ArgumentNullException(nameof(xpath)); - - var xml = GetXml(preview); - var node = vars == null - ? xml.SelectSingleNode(xpath) - : xml.SelectSingleNode(xpath, vars); - return ConvertToDocument(node, preview); - } - - public override IEnumerable GetByXPath(bool preview, string xpath, XPathVariable[] vars) - { - if (xpath == null) throw new ArgumentNullException(nameof(xpath)); - if (string.IsNullOrWhiteSpace(xpath)) return Enumerable.Empty(); - - var xml = GetXml(preview); - var nodes = vars == null - ? xml.SelectNodes(xpath) - : xml.SelectNodes(xpath, vars); - return ConvertToDocuments(nodes, preview); - } - - public override IEnumerable GetByXPath(bool preview, XPathExpression xpath, XPathVariable[] vars) - { - if (xpath == null) throw new ArgumentNullException(nameof(xpath)); - - var xml = GetXml(preview); - var nodes = vars == null - ? xml.SelectNodes(xpath) - : xml.SelectNodes(xpath, vars); - return ConvertToDocuments(nodes, preview); - } - - public override bool HasContent(bool preview) - { - var xml = GetXml(preview); - var node = xml?.SelectSingleNode(XPathStrings.RootDocuments); - return node != null; - } - - public override XPathNavigator CreateNavigator(bool preview) - { - var xml = GetXml(preview); - return xml.CreateNavigator(); - } - - public override XPathNavigator CreateNodeNavigator(int id, bool preview) - { - // hackish - backward compatibility ;-( - - XPathNavigator navigator = null; - - if (preview) - { - var node = _xmlStore.GetPreviewXmlNode(id); - if (node != null) - { - navigator = node.CreateNavigator(); - } - } - else - { - var node = GetXml(false).GetElementById(id.ToInvariantString()); - if (node != null) - { - var doc = new XmlDocument(); - var clone = doc.ImportNode(node, false); - var props = node.SelectNodes("./* [not(@id)]"); - if (props == null) throw new Exception("oops"); - foreach (var n in props.Cast()) - clone.AppendChild(doc.ImportNode(n, true)); - navigator = node.CreateNavigator(); - } - } - - return navigator; - } - - #endregion - - #region Legacy Xml - - private readonly XmlStore _xmlStore; - private XmlDocument _xml; - private readonly PreviewContent _previewContent; - - internal XmlDocument GetXml(bool preview) - { - // not trying to be thread-safe here, that's not the point - - if (preview == false) - { - // if there's a current enlisted reader/writer, use its xml - var tempXml = _xmlStore.TempXml; - if (tempXml != null) return tempXml; - return _xml; - } - - // Xml cache does not support retrieving preview content when not previewing - if (_previewContent == null) - throw new InvalidOperationException("Cannot retrieve preview content when not previewing."); - - // PreviewContent tries to load the Xml once and if it fails, - // it invalidates itself and always return null for XmlContent. - var previewXml = _previewContent.XmlContent; - return previewXml ?? _xml; - } - - internal void Resync(XmlDocument xml) - { - _xml = xml; // re-capture - - // note: we're not resyncing "preview" because that would mean re-building the whole - // preview set which is costly, so basically when previewing, there will be no resync. - - // clear recursive properties cached by XmlPublishedContent.GetProperty - // assume that nothing else is going to cache IPublishedProperty items (else would need to do ByKeySearch) - // NOTE also clears all the media cache properties, which is OK (see media cache) - _appCache.ClearOfType(); - //_appCache.ClearCacheByKeySearch("XmlPublishedCache.PublishedContentCache:RecursiveProperty-"); - } - - #endregion - - #region XPathQuery - - static readonly char[] SlashChar = { '/' }; - - #endregion - - #region Content types - - public override IPublishedContentType GetContentType(int id) => _contentTypeCache.Get(PublishedItemType.Content, id); - - public override IPublishedContentType GetContentType(string alias) => _contentTypeCache.Get(PublishedItemType.Content, alias); - - public override IPublishedContentType GetContentType(Guid key) => _contentTypeCache.Get(PublishedItemType.Content, key); - - #endregion - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs deleted file mode 100644 index c8e5bfaacfce..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs +++ /dev/null @@ -1,698 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.IO; -using System.Linq; -using System.Threading; -using System.Xml.XPath; -using Examine; -using Examine.Search; -using Lucene.Net.Store; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Core.Xml; -using Umbraco.Cms.Infrastructure.Examine; -using Umbraco.Extensions; -using Umbraco.Web.Composing; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - /// - /// An IPublishedMediaStore that first checks for the media in Examine, and then reverts to the database - /// - /// - /// NOTE: In the future if we want to properly cache all media this class can be extended or replaced when these classes/interfaces are exposed publicly. - /// - internal class PublishedMediaCache : PublishedCacheBase, IPublishedMediaCache - { - private readonly IMediaService _mediaService; - private readonly IUserService _userService; - - // by default these are null unless specified by the ctor dedicated to tests - // when they are null the cache derives them from the ExamineManager, see - // method GetExamineManagerSafe(). - // - private readonly ISearcher _searchProvider; - private readonly XmlStore _xmlStore; - private readonly PublishedContentTypeCache _contentTypeCache; - private readonly IEntityXmlSerializer _entitySerializer; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly IVariationContextAccessor _variationContextAccessor; - private readonly IExamineManager _examineManager = new ExamineManager(); - - // must be specified by the ctor - private readonly IAppCache _appCache; - - public PublishedMediaCache(XmlStore xmlStore, IMediaService mediaService, IUserService userService, - IAppCache appCache, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer, - IUmbracoContextAccessor umbracoContextAccessor, IVariationContextAccessor variationContextAccessor) - : base(false) - { - _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); - _userService = userService ?? throw new ArgumentNullException(nameof(userService)); - - _appCache = appCache; - _xmlStore = xmlStore; - _contentTypeCache = contentTypeCache; - _entitySerializer = entitySerializer; - _umbracoContextAccessor = umbracoContextAccessor; - _variationContextAccessor = variationContextAccessor; - } - - /// - /// Generally used for unit testing to use an explicit examine searcher - /// - /// - /// - /// - /// - /// - /// - internal PublishedMediaCache(IMediaService mediaService, IUserService userService, ISearcher searchProvider, IAppCache appCache, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer, IUmbracoContextAccessor umbracoContextAccessor) - : base(false) - { - _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); - _userService = userService ?? throw new ArgumentNullException(nameof(userService)); - _searchProvider = searchProvider ?? throw new ArgumentNullException(nameof(searchProvider)); - _appCache = appCache; - _contentTypeCache = contentTypeCache; - _entitySerializer = entitySerializer; - _umbracoContextAccessor = umbracoContextAccessor; - } - - static PublishedMediaCache() - { - InitializeCacheConfig(); - } - - public override IPublishedContent GetById(bool preview, int nodeId) - { - return GetUmbracoMedia(nodeId); - } - - public override IPublishedContent GetById(bool preview, Guid nodeId) - { - throw new NotImplementedException(); - } - - public override IPublishedContent GetById(bool preview, Udi nodeId) - => throw new NotSupportedException(); - - public override bool HasById(bool preview, int contentId) - { - return GetUmbracoMedia(contentId) != null; - } - - public override IEnumerable GetAtRoot(bool preview, string culture = null) - { - var searchProvider = GetSearchProviderSafe(); - - if (searchProvider != null) - { - try - { - // first check in Examine for the cache values - // +(+parentID:-1) +__IndexType:media - - var criteria = searchProvider.CreateQuery("media"); - var filter = criteria.ParentId(-1).Not().Field(UmbracoExamineFieldNames.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard()); - - var result = filter.Execute(); - if (result != null) - return result.Select(x => CreateFromCacheValues(ConvertFromSearchResult(x))); - } - catch (Exception ex) - { - if (ex is FileNotFoundException) - { - //Currently examine is throwing FileNotFound exceptions when we have a load balanced filestore and a node is published in umbraco - //See this thread: http://examine.cdodeplex.com/discussions/264341 - //Catch the exception here for the time being, and just fallback to GetMedia - // TODO: Need to fix examine in LB scenarios! - Current.Logger.LogError(ex, "Could not load data from Examine index for media"); - } - else if (ex is ObjectDisposedException) - { - //If the app domain is shutting down and the site is under heavy load the index reader will be closed and it really cannot - //be re-opened since the app domain is shutting down. In this case we have no option but to try to load the data from the db. - Current.Logger.LogError(ex, "Could not load data from Examine index for media, the app domain is most likely in a shutdown state"); - } - else throw; - } - } - - //something went wrong, fetch from the db - - var rootMedia = _mediaService.GetRootMedia(); - return rootMedia.Select(m => GetUmbracoMedia(m.Id)); - } - - public override IPublishedContent GetSingleByXPath(bool preview, string xpath, XPathVariable[] vars) - { - throw new NotImplementedException("PublishedMediaCache does not support XPath."); - //var navigator = CreateNavigator(preview); - //var iterator = navigator.Select(xpath, vars); - //return GetSingleByXPath(iterator); - } - - public override IPublishedContent GetSingleByXPath(bool preview, XPathExpression xpath, XPathVariable[] vars) - { - throw new NotImplementedException("PublishedMediaCache does not support XPath."); - //var navigator = CreateNavigator(preview); - //var iterator = navigator.Select(xpath, vars); - //return GetSingleByXPath(iterator); - } - - private IPublishedContent GetSingleByXPath(XPathNodeIterator iterator) - { - throw new NotImplementedException("PublishedMediaCache does not support XPath."); - //if (iterator.MoveNext() == false) return null; - //var idAttr = iterator.Current.GetAttribute("id", ""); - //int id; - //return int.TryParse(idAttr, out id) ? GetUmbracoMedia(id) : null; - } - - public override IEnumerable GetByXPath(bool preview, string xpath, XPathVariable[] vars) - { - throw new NotImplementedException("PublishedMediaCache does not support XPath."); - //var navigator = CreateNavigator(preview); - //var iterator = navigator.Select(xpath, vars); - //return GetByXPath(iterator); - } - - public override IEnumerable GetByXPath(bool preview, XPathExpression xpath, XPathVariable[] vars) - { - throw new NotImplementedException("PublishedMediaCache does not support XPath."); - //var navigator = CreateNavigator(preview); - //var iterator = navigator.Select(xpath, vars); - //return GetByXPath(iterator); - } - - private IEnumerable GetByXPath(XPathNodeIterator iterator) - { - while (iterator.MoveNext()) - { - var idAttr = iterator.Current.GetAttribute("id", ""); - int id; - if (int.TryParse(idAttr, out id)) - yield return GetUmbracoMedia(id); - } - } - - public override XPathNavigator CreateNavigator(bool preview) - { - throw new NotImplementedException("PublishedMediaCache does not support XPath."); - //var doc = _xmlStore.GetMediaXml(); - //return doc.CreateNavigator(); - } - - public override XPathNavigator CreateNodeNavigator(int id, bool preview) - { - // preview is ignored for media cache - - // this code is mostly used when replacing old media.ToXml() code, and that code - // stored the XML attached to the media itself - so for some time in memory - so - // unless we implement some sort of cache here, we're probably degrading perfs. - - XPathNavigator navigator = null; - var node = _xmlStore.GetMediaXmlNode(id); - if (node != null) - { - navigator = node.CreateNavigator(); - } - return navigator; - } - - public override bool HasContent(bool preview) { throw new NotImplementedException(); } - - private ISearcher GetSearchProviderSafe() - { - if (_searchProvider != null) - return _searchProvider; - - try - { - return _examineManager.TryGetIndex(Constants.UmbracoIndexes.InternalIndexName, out var index) ? index.GetSearcher() : null; - } - catch (FileNotFoundException) - { - //Currently examine is throwing FileNotFound exceptions when we have a load balanced filestore and a node is published in umbraco - //See this thread: http://examine.cdodeplex.com/discussions/264341 - //Catch the exception here for the time being, and just fallback to GetMedia - // TODO: Need to fix examine in LB scenarios! - } - catch (NullReferenceException) - { - //This will occur when the search provider cannot be initialized. In newer examine versions the initialization is lazy and therefore - // the manager will return the singleton without throwing initialization errors, however if examine isn't configured correctly a null - // reference error will occur because the examine settings are null. - } - catch (ObjectDisposedException) - { - //If the app domain is shutting down and the site is under heavy load the index reader will be closed and it really cannot - //be re-opened since the app domain is shutting down. In this case we have no option but to try to load the data from the db. - } - return null; - } - - private IPublishedContent GetUmbracoMedia(int id) - { - // this recreates an IPublishedContent and model each time - // it is called, but at least it should NOT hit the database - // nor Lucene each time, relying on the memory cache instead - - if (id <= 0) return null; // fail fast - - var cacheValues = GetCacheValues(id, GetUmbracoMediaCacheValues); - - return cacheValues == null ? null : CreateFromCacheValues(cacheValues); - } - - private CacheValues GetUmbracoMediaCacheValues(int id) - { - var searchProvider = GetSearchProviderSafe(); - - if (searchProvider != null) - { - try - { - // first check in Examine as this is WAY faster - // - // the filter will create a query like this: - // +(+__NodeId:3113 -__Path:-1,-21,*) +__IndexType:media - // - // note that since the use of the wildcard, it automatically escapes it in Lucene. - - var criteria = searchProvider.CreateQuery("media"); - var filter = criteria.Id(id.ToInvariantString()).Not().Field(UmbracoExamineFieldNames.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard()); - - var result = filter.Execute().FirstOrDefault(); - if (result != null) return ConvertFromSearchResult(result); - } - catch (Exception ex) - { - if (ex is FileNotFoundException) - { - //Currently examine is throwing FileNotFound exceptions when we have a load balanced filestore and a node is published in umbraco - //See this thread: http://examine.cdodeplex.com/discussions/264341 - //Catch the exception here for the time being, and just fallback to GetMedia - // TODO: Need to fix examine in LB scenarios! - Current.Logger.LogError(ex, "Could not load data from Examine index for media"); - } - else if (ex is ObjectDisposedException) - { - //If the app domain is shutting down and the site is under heavy load the index reader will be closed and it really cannot - //be re-opened since the app domain is shutting down. In this case we have no option but to try to load the data from the db. - Current.Logger.LogError(ex, "Could not load data from Examine index for media, the app domain is most likely in a shutdown state"); - } - else throw; - } - } - - // don't log a warning here, as it can flood the log in case of eg a media picker referencing a media - // that has been deleted, hence is not in the Examine index anymore (for a good reason). try to get - // the media from the service, first - var media = _mediaService.GetById(id); - if (media == null || media.Trashed) return null; // not found, ok - - // so, the media was not found in Examine's index *yet* it exists, which probably indicates that - // the index is corrupted. Or not up-to-date. Log a warning, but only once, and only if seeing the - // error more that a number of times. - - var miss = Interlocked.CompareExchange(ref _examineIndexMiss, 0, 0); // volatile read - if (miss < ExamineIndexMissMax && Interlocked.Increment(ref _examineIndexMiss) == ExamineIndexMissMax) - Current.Logger.LogWarning("Failed ({ExamineIndexMissMax} times) to retrieve medias from Examine index and had to load" - + " them from DB. This may indicate that the Examine index is corrupted.", ExamineIndexMissMax); - - return ConvertFromIMedia(media); - } - - private const int ExamineIndexMissMax = 10; - private int _examineIndexMiss; - - internal CacheValues ConvertFromXPathNodeIterator(XPathNodeIterator media, int id) - { - if (media?.Current != null) - { - return media.Current.Name.InvariantEquals("error") - ? null - : ConvertFromXPathNavigator(media.Current); - } - - Current.Logger.LogWarning("Could not retrieve media {MediaId} from Examine index or from legacy library.GetMedia method", id); - - return null; - } - - internal CacheValues ConvertFromSearchResult(ISearchResult searchResult) - { - // note: fixing fields in 7.x, removed by Shan for 8.0 - - return new CacheValues - { - Values = searchResult.Values, - FromExamine = true - }; - } - - internal CacheValues ConvertFromXPathNavigator(XPathNavigator xpath, bool forceNav = false) - { - if (xpath == null) throw new ArgumentNullException(nameof(xpath)); - - var values = new Dictionary { { "nodeName", xpath.GetAttribute("nodeName", "") } }; - values["nodeTypeAlias"] = xpath.Name; - - var result = xpath.SelectChildren(XPathNodeType.Element); - //add the attributes e.g. id, parentId etc - if (result.Current != null && result.Current.HasAttributes) - { - if (result.Current.MoveToFirstAttribute()) - { - //checking for duplicate keys because of the 'nodeTypeAlias' might already be added above. - if (values.ContainsKey(result.Current.Name) == false) - { - values[result.Current.Name] = result.Current.Value; - } - while (result.Current.MoveToNextAttribute()) - { - if (values.ContainsKey(result.Current.Name) == false) - { - values[result.Current.Name] = result.Current.Value; - } - } - result.Current.MoveToParent(); - } - } - // because, migration - if (values.ContainsKey("key") == false) - values["key"] = Guid.Empty.ToString(); - //add the user props - while (result.MoveNext()) - { - if (result.Current != null && result.Current.HasAttributes == false) - { - var value = result.Current.Value; - if (string.IsNullOrEmpty(value)) - { - if (result.Current.HasAttributes || result.Current.SelectChildren(XPathNodeType.Element).Count > 0) - { - value = result.Current.OuterXml; - } - } - values[result.Current.Name] = value; - } - } - - return new CacheValues - { - Values = values, - XPath = forceNav ? xpath : null // outside of tests we do NOT want to cache the navigator! - }; - } - - internal CacheValues ConvertFromIMedia(IMedia media) - { - var values = new Dictionary(); - - var creator = _userService.GetProfileById(media.CreatorId); - var creatorName = creator == null ? "" : creator.Name; - - values["id"] = media.Id.ToString(); - values["key"] = media.Key.ToString(); - values["parentID"] = media.ParentId.ToString(); - values["level"] = media.Level.ToString(); - values["creatorID"] = media.CreatorId.ToString(); - values["creatorName"] = creatorName; - values["writerID"] = media.CreatorId.ToString(); - values["writerName"] = creatorName; - values["template"] = "0"; - values["urlName"] = ""; - values["sortOrder"] = media.SortOrder.ToString(); - values["createDate"] = media.CreateDate.ToString("yyyy-MM-dd HH:mm:ss"); - values["updateDate"] = media.UpdateDate.ToString("yyyy-MM-dd HH:mm:ss"); - values["nodeName"] = media.Name; - values["path"] = media.Path; - values["nodeType"] = media.ContentType.Id.ToString(); - values["nodeTypeAlias"] = media.ContentType.Alias; - - // add the user props - foreach (var prop in media.Properties) - values[prop.Alias] = prop.GetValue()?.ToString(); - - return new CacheValues - { - Values = values - }; - } - - /// - /// We will need to first check if the document was loaded by Examine, if so we'll need to check if this property exists - /// in the results, if it does not, then we'll have to revert to looking up in the db. - /// - /// - /// - /// - private IPublishedProperty GetProperty(DictionaryPublishedContent dd, string alias) - { - //lets check if the alias does not exist on the document. - //NOTE: Examine will not index empty values and we do not output empty XML Elements to the cache - either of these situations - // would mean that the property is missing from the collection whether we are getting the value from Examine or from the library media cache. - if (dd.Properties.All(x => x.Alias.InvariantEquals(alias) == false)) - { - return null; - } - - if (dd.LoadedFromExamine) - { - //We are going to check for a special field however, that is because in some cases we store a 'Raw' - //value in the index such as for xml/html. - var rawValue = dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(UmbracoExamineFieldNames.RawFieldPrefix + alias)); - return rawValue - ?? dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(alias)); - } - - //if its not loaded from examine, then just return the property - return dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(alias)); - } - - /// - /// A Helper methods to return the children for media whether it is based on examine or xml - /// - /// - /// - /// - private IEnumerable GetChildrenMedia(int parentId, XPathNavigator xpath = null) - { - // if there *is* a navigator, directly look it up - if (xpath != null) - { - return ToIPublishedContent(parentId, xpath); - } - - // otherwise, try examine first, then re-look it up - var searchProvider = GetSearchProviderSafe(); - - if (searchProvider != null) - { - try - { - //first check in Examine as this is WAY faster - var criteria = searchProvider.CreateQuery("media"); - - var filter = criteria.ParentId(parentId).Not().Field(UmbracoExamineFieldNames.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard()) - .OrderBy(new SortableField("sortOrder", SortType.Int)); - //the above filter will create a query like this, NOTE: That since the use of the wildcard, it automatically escapes it in Lucene. - //+(+parentId:3113 -__Path:-1,-21,*) +__IndexType:media - - // sort with the Sort field (updated for 8.0) - var results = filter.Execute(); - - if (results.Any()) - { - // var medias = results.Select(ConvertFromSearchResult); - var medias = results.Select(x => - { - int nid; - if (int.TryParse(x["__NodeId"], out nid) == false && int.TryParse(x["NodeId"], out nid) == false) - throw new Exception("Failed to extract NodeId from search result."); - var cacheValues = GetCacheValues(nid, id => ConvertFromSearchResult(x)); - return CreateFromCacheValues(cacheValues); - }); - - return medias; - } - - //if there's no result then return null. Previously we defaulted back to library.GetMedia below - //but this will always get called for when we are getting descendants since many items won't have - //children and then we are hitting the database again! - //So instead we're going to rely on Examine to have the correct results like it should. - return Enumerable.Empty(); - } - catch (FileNotFoundException) - { - //Currently examine is throwing FileNotFound exceptions when we have a load balanced filestore and a node is published in umbraco - //See this thread: http://examine.cdodeplex.com/discussions/264341 - //Catch the exception here for the time being, and just fallback to GetMedia - } - } - - // falling back to get media - // was library.GetMedia which had its own cache, but MediaService *also* caches - // so, library.GetMedia is gone and now we directly work with MediaService - // (code below copied from what library was doing) - var media = _mediaService.GetById(parentId); - if (media == null) - { - return Enumerable.Empty(); - } - - var serialized = _entitySerializer.Serialize(media, true); - - var mediaIterator = serialized.CreateNavigator().Select("/"); - - return mediaIterator.Current == null - ? Enumerable.Empty() - : ToIPublishedContent(parentId, mediaIterator.Current); - } - - - internal IEnumerable ToIPublishedContent(int parentId, XPathNavigator xpath) - { - var mediaList = new List(); - - // this is so bad, really - var item = xpath.Select("//*[@id='" + parentId + "']"); - if (item.Current == null) - return Enumerable.Empty(); - var items = item.Current.SelectChildren(XPathNodeType.Element); - - // and this does not work, because... meh - //var q = "//* [@id='" + parentId + "']/* [@id]"; - //var items = xpath.Select(q); - - foreach (XPathNavigator itemm in items) - { - int id; - if (int.TryParse(itemm.GetAttribute("id", ""), out id) == false) - continue; // uh? - var captured = itemm; - var cacheValues = GetCacheValues(id, idd => ConvertFromXPathNavigator(captured)); - mediaList.Add(CreateFromCacheValues(cacheValues)); - } - - return mediaList; - } - - - internal void Resync() - { - // clear recursive properties cached by XmlPublishedContent.GetProperty - // assume that nothing else is going to cache IPublishedProperty items (else would need to do ByKeySearch) - // NOTE all properties cleared when clearing the content cache (see content cache) - //_appCache.ClearCacheObjectTypes(); - //_appCache.ClearCacheByKeySearch("XmlPublishedCache.PublishedMediaCache:RecursiveProperty-"); - } - - #region Content types - - public override IPublishedContentType GetContentType(int id) => _contentTypeCache.Get(PublishedItemType.Media, id); - - public override IPublishedContentType GetContentType(string alias) => _contentTypeCache.Get(PublishedItemType.Media, alias); - - public override IPublishedContentType GetContentType(Guid key) => _contentTypeCache.Get(PublishedItemType.Media, key); - - public override IEnumerable GetByContentType(IPublishedContentType contentType) - { - throw new NotSupportedException(); - } - - #endregion - - // REFACTORING - - // caching the basic atomic values - and the parent id - // but NOT caching actual parent nor children and NOT even - // the list of children ids - BUT caching the path - - internal class CacheValues - { - public IReadOnlyDictionary Values { get; set; } - public XPathNavigator XPath { get; set; } - public bool FromExamine { get; set; } - } - - public const string PublishedMediaCacheKey = "MediaCacheMeh."; - private const int PublishedMediaCacheTimespanSeconds = 4 * 60; // 4 mins - private static TimeSpan _publishedMediaCacheTimespan; - private static bool _publishedMediaCacheEnabled; - - private static void InitializeCacheConfig() - { - _publishedMediaCacheEnabled = true; - _publishedMediaCacheTimespan = TimeSpan.FromSeconds(PublishedMediaCacheTimespanSeconds); - } - - internal IPublishedContent CreateFromCacheValues(CacheValues cacheValues) - { - var content = new DictionaryPublishedContent( - cacheValues.Values, - parentId => parentId < 0 ? null : GetUmbracoMedia(parentId), - GetChildrenMedia, - GetProperty, - _appCache, - _variationContextAccessor, - _contentTypeCache, - cacheValues.XPath, // though, outside of tests, that should be null - cacheValues.FromExamine - ); - return content.CreateModel(Current.PublishedModelFactory); - } - - private static CacheValues GetCacheValues(int id, Func func) - { - if (_publishedMediaCacheEnabled == false) - return func(id); - - var cache = Current.AppCaches.RuntimeCache; - var key = PublishedMediaCacheKey + id; - return (CacheValues)cache.Get(key, () => func(id), _publishedMediaCacheTimespan); - } - - internal static void ClearCache(int id) - { - var cache = Current.AppCaches.RuntimeCache; - var sid = id.ToString(); - var key = PublishedMediaCacheKey + sid; - - // we do clear a lot of things... but the cache refresher is somewhat - // convoluted and it's hard to tell what to clear exactly ;-( - - // clear the parent - NOT (why?) - //var exist = (CacheValues) cache.GetCacheItem(key); - //if (exist != null) - // cache.ClearCacheItem(PublishedMediaCacheKey + GetValuesValue(exist.Values, "parentID")); - - // clear the item - cache.Clear(key); - - // clear all children - in case we moved and their path has changed - var fid = "/" + sid + "/"; - cache.ClearOfType((k, v) => - GetValuesValue(v.Values, "path", "__Path").Contains(fid)); - } - - private static string GetValuesValue(IReadOnlyDictionary d, params string[] keys) - { - string value = null; - var ignored = keys.Any(x => d.TryGetValue(x, out value)); - return value ?? ""; - } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMember.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMember.cs deleted file mode 100644 index a885af1475c1..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMember.cs +++ /dev/null @@ -1,154 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.Membership; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Services; -using Umbraco.Extensions; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - /// - /// Exposes a member object as IPublishedContent - /// - public sealed class PublishedMember : PublishedContentBase - { - private readonly IMember _member; - private readonly IMembershipUser _membershipUser; - private readonly IPublishedProperty[] _properties; - private readonly IPublishedContentType _publishedMemberType; - - public PublishedMember( - IMember member, - IPublishedContentType publishedMemberType, - IVariationContextAccessor variationContextAccessor) : base(variationContextAccessor) - { - _member = member ?? throw new ArgumentNullException(nameof(member)); - _membershipUser = member; - _publishedMemberType = publishedMemberType ?? throw new ArgumentNullException(nameof(publishedMemberType)); - - // RawValueProperty is used for two things here - // - for the 'map properties' thing that we should really get rid of - // - for populating properties that every member should always have, and that we force-create - // if they are not part of the member type properties - in which case they are created as - // simple raw properties - which are completely invariant - - var properties = new List(); - foreach (var propertyType in _publishedMemberType.PropertyTypes) - { - var property = _member.Properties[propertyType.Alias]; - if (property == null) continue; - - properties.Add(new RawValueProperty(propertyType, this, property.GetValue())); - } - EnsureMemberProperties(properties); - _properties = properties.ToArray(); - } - - #region Membership provider member properties - - public string Email => _membershipUser.Email; - - public string UserName => _membershipUser.Username; - - public string Comments => _membershipUser.Comments; - - public bool IsApproved => _membershipUser.IsApproved; - - public bool IsLockedOut => _membershipUser.IsLockedOut; - - public DateTime LastLockoutDate => _membershipUser.LastLockoutDate; - - public DateTime CreationDate => _membershipUser.CreateDate; - - public DateTime LastLoginDate => _membershipUser.LastLoginDate; - - public DateTime LastPasswordChangeDate => _membershipUser.LastPasswordChangeDate; - - #endregion - - #region IPublishedContent - - public override PublishedItemType ItemType => PublishedItemType.Member; - - public override bool IsDraft(string culture = null) => false; - - public override bool IsPublished(string culture = null) => true; - - public override IPublishedContent Parent => null; - - public override IEnumerable Children => Enumerable.Empty(); - - public override IEnumerable ChildrenForAllCultures => Enumerable.Empty(); - - public override IEnumerable Properties => _properties; - - public override IPublishedProperty GetProperty(string alias) - { - return _properties.FirstOrDefault(x => x.Alias.InvariantEquals(alias)); - } - - private void EnsureMemberProperties(List properties) - { - var aliases = properties.Select(x => x.Alias).ToList(); - - EnsureMemberProperty(properties, aliases, nameof(IMember.Email), Email); - EnsureMemberProperty(properties, aliases, nameof(IMember.Username), UserName); - EnsureMemberProperty(properties, aliases, nameof(IMember.Comments), Comments); - EnsureMemberProperty(properties, aliases, nameof(IMember.IsApproved), IsApproved); - EnsureMemberProperty(properties, aliases, nameof(IMember.IsLockedOut), IsLockedOut); - EnsureMemberProperty(properties, aliases, nameof(IMember.LastLockoutDate), LastLockoutDate); - EnsureMemberProperty(properties, aliases, nameof(IMember.CreateDate), CreateDate); - EnsureMemberProperty(properties, aliases, nameof(IMember.LastLoginDate), LastLoginDate); - EnsureMemberProperty(properties, aliases, nameof(IMember.LastPasswordChangeDate), LastPasswordChangeDate); - } - - private void EnsureMemberProperty(List properties, List aliases, string alias, object value) - { - // if the property already has a value, nothing to do - if (aliases.Contains(alias)) return; - - // if not a property type, ignore - var propertyType = ContentType.GetPropertyType(alias); - if (propertyType == null) return; - - // create a raw-value property - // note: throws if propertyType variations is not InvariantNeutral - var property = new RawValueProperty(propertyType, this, value); - properties.Add(property); - } - - public override IPublishedContentType ContentType => _publishedMemberType; - - public override int Id => _member.Id; - - public override Guid Key => _member.Key; - - public override int? TemplateId => throw new NotSupportedException(); - - public override int SortOrder => 0; - - public override string Name => _member.Name; - - public override IReadOnlyDictionary Cultures => throw new NotSupportedException(); - - public override string UrlSegment => throw new NotSupportedException(); - - public override int WriterId => _member.CreatorId; - - public override int CreatorId => _member.CreatorId; - - public override string Path => _member.Path; - - public override DateTime CreateDate => _member.CreateDate; - - public override DateTime UpdateDate => _member.UpdateDate; - - public override int Level => _member.Level; - - public DateTime LastPasswordChangedDate => throw new NotImplementedException(); - - #endregion - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMemberCache.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMemberCache.cs deleted file mode 100644 index 1faa0ee94809..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMemberCache.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Extensions; -using Umbraco.Web.Composing; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - class PublishedMemberCache : IPublishedMemberCache - { - private readonly PublishedContentTypeCache _contentTypeCache; - private readonly IVariationContextAccessor _variationContextAccessor; - - public PublishedMemberCache(PublishedContentTypeCache contentTypeCache, IVariationContextAccessor variationContextAccessor) - { - _contentTypeCache = contentTypeCache; - _variationContextAccessor = variationContextAccessor; - } - - public IPublishedContent Get(IMember member) - { - var type = _contentTypeCache.Get(PublishedItemType.Member, member.ContentTypeId); - return new PublishedMember(member, type, _variationContextAccessor) - .CreateModel(Current.PublishedModelFactory); - } - - #region Content types - - public IPublishedContentType GetContentType(int id) => _contentTypeCache.Get(PublishedItemType.Member, id); - - public IPublishedContentType GetContentType(string alias) => _contentTypeCache.Get(PublishedItemType.Member, alias); - - #endregion - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedSnapshot.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedSnapshot.cs deleted file mode 100644 index 11abce0e645f..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/PublishedSnapshot.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.PublishedCache; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - /// - /// Implements a published snapshot. - /// - class PublishedSnapshot : IPublishedSnapshot - { - /// - /// Initializes a new instance of the class with a content cache - /// and a media cache. - /// - public PublishedSnapshot( - PublishedContentCache contentCache, - PublishedMediaCache mediaCache, - PublishedMemberCache memberCache, - DomainCache domainCache) - { - Content = contentCache; - Media = mediaCache; - Members = memberCache; - Domains = domainCache; - } - - /// - public IPublishedContentCache Content { get; } - - /// - public IPublishedMediaCache Media { get; } - - /// - public IPublishedMemberCache Members { get; } - - /// - public IDomainCache Domains { get; } - - /// - public IAppCache SnapshotCache => null; - - /// - public IAppCache ElementsCache => null; - - /// - public IDisposable ForcedPreview(bool preview, Action callback = null) - { - // the XML cache does not support forcing preview, really, so, just pretend... - return new ForcedPreviewObject(); - } - - private class ForcedPreviewObject : DisposableObjectSlim - { - protected override void DisposeResources() - { } - } - - public void Dispose() - { } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/RoutesCache.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/RoutesCache.cs deleted file mode 100644 index 71f2f421ffb4..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/RoutesCache.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System.Collections.Concurrent; -using System.Collections.Generic; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - // Note: RoutesCache closely follows the caching strategy dating from v4, which - // is obviously broken in many ways (eg it's a global cache but relying to some - // extend to the content cache, which itself is local to each request...). - // Not going to fix it anyway. - - class RoutesCache - { - private ConcurrentDictionary _routes; - private ConcurrentDictionary _nodeIds; - - // NOTE - // RoutesCache is cleared by - // - ContentTypeCacheRefresher, whenever anything happens to any content type - // - DomainCacheRefresher, whenever anything happens to any domain - // - XmlStore, whenever anything happens to the XML cache - - /// - /// Initializes a new instance of the class. - /// - public RoutesCache() - { - Clear(); - } - - /// - /// Used ONLY for unit tests - /// - /// - internal IDictionary GetCachedRoutes() - { - return _routes; - } - - /// - /// Used ONLY for unit tests - /// - /// - internal IDictionary GetCachedIds() - { - return _nodeIds; - } - - #region Public - - /// - /// Stores a route for a node. - /// - /// The node identified. - /// The route. - /// A value indicating whether the value can be trusted for inbound routing. - public void Store(int nodeId, string route, bool trust) - { - _routes.AddOrUpdate(nodeId, i => route, (i, s) => route); - if (trust) - _nodeIds.AddOrUpdate(route, i => nodeId, (i, s) => nodeId); - } - - /// - /// Gets a route for a node. - /// - /// The node identifier. - /// The route for the node, else null. - public string GetRoute(int nodeId) - { - string val; - _routes.TryGetValue(nodeId, out val); - return val; - } - - /// - /// Gets a node for a route. - /// - /// The route. - /// The node identified for the route, else zero. - public int GetNodeId(string route) - { - int val; - _nodeIds.TryGetValue(route, out val); - return val; - } - - /// - /// Clears the route for a node. - /// - /// The node identifier. - public void ClearNode(int nodeId) - { - string route; - if (_routes.TryRemove(nodeId, out route)) - { - int id; - _nodeIds.TryRemove(route, out id); - } - } - - /// - /// Clears all routes. - /// - public void Clear() - { - _routes = new ConcurrentDictionary(); - _nodeIds = new ConcurrentDictionary(); - } - - #endregion - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/SafeXmlReaderWriter.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/SafeXmlReaderWriter.cs deleted file mode 100644 index fe560e4c93d0..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/SafeXmlReaderWriter.cs +++ /dev/null @@ -1,154 +0,0 @@ -using System; -using System.Xml; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Scoping; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - // TODO: should be a ScopeContextualBase - internal class SafeXmlReaderWriter : IDisposable - { - private readonly bool _scoped; - private readonly Action _refresh; - private readonly Action _apply; - private IDisposable _releaser; - private bool _applyChanges; - private XmlDocument _xml, _origXml; - private bool _using; - private bool _registerXmlChange; - - // the default enlist priority is 100 - // enlist with a lower priority to ensure that anything "default" has a clean xml - private const int EnlistPriority = 60; - private const string EnlistKey = "safeXmlReaderWriter"; - - private SafeXmlReaderWriter(IDisposable releaser, XmlDocument xml, Action refresh, Action apply, bool isWriter, bool scoped) - { - _releaser = releaser; - _refresh = refresh; - _apply = apply; - _scoped = scoped; - - IsWriter = isWriter; - - _xml = IsWriter ? Clone(xml) : xml; - } - - public static SafeXmlReaderWriter Get(IScopeProvider scopeProvider) - { - return scopeProvider?.Context?.GetEnlisted(EnlistKey); - } - - public static SafeXmlReaderWriter Get(IScopeProvider scopeProvider, SystemLock xmlLock, XmlDocument xml, Action refresh, Action apply, bool writer) - { - var scopeContext = scopeProvider.Context; - - // no real scope = just create a reader/writer instance - if (scopeContext == null) - { - // obtain exclusive access to xml and create reader/writer - var releaser = xmlLock.Lock(); - return new SafeXmlReaderWriter(releaser, xml, refresh, apply, writer, false); - } - - // get or create an enlisted reader/writer - var rw = scopeContext.Enlist(EnlistKey, - () => // creator - { - // obtain exclusive access to xml and create reader/writer - var releaser = xmlLock.Lock(); - return new SafeXmlReaderWriter(releaser, xml, refresh, apply, writer, true); - }, - (completed, item) => // action - { - item.DisposeForReal(completed); - }, EnlistPriority); - - // ensure it's not already in-use - should never happen, just being super safe - if (rw._using) - throw new InvalidOperationException("panic: used."); - rw._using = true; - - return rw; - } - - public bool IsWriter { get; private set; } - - public void UpgradeToWriter(bool auto) - { - if (IsWriter) - throw new InvalidOperationException("Already a writer."); - IsWriter = true; - - _xml = Clone(_xml); - } - - // for tests - internal static Action Cloning { get; set; } - - private XmlDocument Clone(XmlDocument xml) - { - Cloning?.Invoke(); - if (_origXml != null) - throw new Exception("panic."); - _origXml = xml; - return (XmlDocument) xml?.CloneNode(true); - } - - public XmlDocument Xml - { - get => _xml; - set - { - if (IsWriter == false) - throw new InvalidOperationException("Not a writer."); - _xml = value; - } - } - - // registerXmlChange indicates whether to do what should be done when Xml changes, - // that is, to request that the file be written to disk - something we don't want - // to do if we're committing Xml precisely after we've read from disk! - public void AcceptChanges(bool registerXmlChange = true) - { - if (IsWriter == false) - throw new InvalidOperationException("Not a writer."); - - _applyChanges = true; - _registerXmlChange |= registerXmlChange; - } - - private void DisposeForReal(bool completed) - { - if (IsWriter) - { - // apply changes, or restore the original xml for the current request - if (_applyChanges && completed) - _apply(_xml, _registerXmlChange); - else - _refresh(_origXml); - } - - // release the lock - _releaser.Dispose(); - _releaser = null; - } - - public void Dispose() - { - _using = false; - - if (_scoped == false) - { - // really dispose - DisposeForReal(true); - } - else - { - // don't really dispose, - // just apply the changes for the current request - _refresh(_xml); - } - } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/UmbracoContextCache.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/UmbracoContextCache.cs deleted file mode 100644 index d1a3340b067f..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/UmbracoContextCache.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Collections.Concurrent; -using System.Runtime.CompilerServices; -using Umbraco.Cms.Core.Web; -using Umbraco.Web; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - static class UmbracoContextCache - { - static readonly ConditionalWeakTable> Caches - = new ConditionalWeakTable>(); - - public static ConcurrentDictionary Current - { - get - { - var umbracoContext = Umbraco.Web.Composing.Current.UmbracoContext; - - // will get or create a value - // a ConditionalWeakTable is thread-safe - // does not prevent the context from being disposed, and then the dictionary will be disposed too - return umbracoContext == null ? null : Caches.GetOrCreateValue(umbracoContext); - } - } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedContent.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedContent.cs deleted file mode 100644 index aa90f0dbfa03..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedContent.cs +++ /dev/null @@ -1,441 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml; -using System.Xml.Serialization; -using System.Xml.XPath; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Extensions; -using Umbraco.Web.Composing; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - /// - /// Represents an IPublishedContent which is created based on an Xml structure. - /// - [Serializable] - [XmlType(Namespace = "http://umbraco.org/webservices/")] - internal class XmlPublishedContent : PublishedContentBase - { - private XmlPublishedContent( - XmlNode xmlNode, - bool isPreviewing, - IAppCache appCache, - PublishedContentTypeCache contentTypeCache, - IVariationContextAccessor variationContextAccessor): base(variationContextAccessor) - { - _xmlNode = xmlNode; - _isPreviewing = isPreviewing; - - _appCache = appCache; - _contentTypeCache = contentTypeCache; - _variationContextAccessor = variationContextAccessor; - } - - private readonly XmlNode _xmlNode; - private readonly bool _isPreviewing; - private readonly IAppCache _appCache; // at snapshot/request level (see PublishedContentCache) - private readonly PublishedContentTypeCache _contentTypeCache; - private readonly IVariationContextAccessor _variationContextAccessor; - - private readonly object _initializeLock = new object(); - - private bool _nodeInitialized; - private bool _parentInitialized; - private bool _childrenInitialized; - - private IEnumerable _children = Enumerable.Empty(); - private IPublishedContent _parent; - - private IPublishedContentType _contentType; - private Dictionary _properties; - - private int _id; - private Guid _key; - private int _template; - private string _name; - private string _docTypeAlias; - private int _docTypeId; - private int _writerId; - private int _creatorId; - private string _urlName; - private string _path; - private DateTime _createDate; - private DateTime _updateDate; - private int _sortOrder; - private int _level; - private bool _isDraft; - - - public override IEnumerable Children - { - get - { - EnsureNodeInitialized(andChildren: true); - return _children; - } - } - - public override IEnumerable ChildrenForAllCultures => Children; - - public override IPublishedProperty GetProperty(string alias) - { - EnsureNodeInitialized(); - IPublishedProperty property; - return _properties.TryGetValue(alias, out property) ? property : null; - } - - public override PublishedItemType ItemType => PublishedItemType.Content; - - public override IPublishedContent Parent - { - get - { - EnsureNodeInitialized(andParent: true); - return _parent; - } - } - - public override int Id - { - get - { - EnsureNodeInitialized(); - return _id; - } - } - - public override Guid Key - { - get - { - EnsureNodeInitialized(); - return _key; - } - } - - public override int? TemplateId - { - get - { - EnsureNodeInitialized(); - return _template; - } - } - - public override int SortOrder - { - get - { - EnsureNodeInitialized(); - return _sortOrder; - } - } - - public override string Name - { - get - { - EnsureNodeInitialized(); - return _name; - } - } - - private Dictionary _cultures; - - private Dictionary GetCultures() - { - EnsureNodeInitialized(); - return new Dictionary { { "", new PublishedCultureInfo("", _name, _urlName, _updateDate) } }; - } - - public override IReadOnlyDictionary Cultures => _cultures ?? (_cultures = GetCultures()); - - public override int WriterId - { - get - { - EnsureNodeInitialized(); - return _writerId; - } - } - - public override int CreatorId - { - get - { - EnsureNodeInitialized(); - return _creatorId; - } - } - - public override string Path - { - get - { - EnsureNodeInitialized(); - return _path; - } - } - - public override DateTime CreateDate - { - get - { - EnsureNodeInitialized(); - return _createDate; - } - } - - public override DateTime UpdateDate - { - get - { - EnsureNodeInitialized(); - return _updateDate; - } - } - - public override string UrlSegment - { - get - { - EnsureNodeInitialized(); - return _urlName; - } - } - - public override int Level - { - get - { - EnsureNodeInitialized(); - return _level; - } - } - - public override bool IsDraft(string culture = null) - { - EnsureNodeInitialized(); - return _isDraft; // bah - } - - public override bool IsPublished(string culture = null) - { - EnsureNodeInitialized(); - return true; // Intentionally not implemented, because the XmlPublishedContent should not support this. - } - - public override IEnumerable Properties - { - get - { - EnsureNodeInitialized(); - return _properties.Values; - } - } - - public override IPublishedContentType ContentType - { - get - { - EnsureNodeInitialized(); - return _contentType; - } - } - - private void InitializeParent() - { - var parent = _xmlNode?.ParentNode; - if (parent == null) return; - - if (parent.Attributes?.GetNamedItem("isDoc") != null) - _parent = Get(parent, _isPreviewing, _appCache, _contentTypeCache, _variationContextAccessor); - - _parentInitialized = true; - } - - private void EnsureNodeInitialized(bool andChildren = false, bool andParent = false) - { - // In *theory* XmlPublishedContent are a per-request thing, and so should not - // end up being involved into multi-threaded situations - however, it's been - // reported that some users ended up seeing 100% CPU due to infinite loops in - // the properties dictionary in InitializeNode, which would indicate that the - // dictionary *is* indeed involved in some multi-threaded operation. No idea - // what users are doing that cause this, but let's be friendly and use a true - // lock around initialization. - - lock (_initializeLock) - { - if (_nodeInitialized == false) InitializeNode(); - if (andChildren && _childrenInitialized == false) InitializeChildren(); - if (andParent && _parentInitialized == false) InitializeParent(); - } - } - - private void InitializeNode() - { - InitializeNode(this, _xmlNode, _isPreviewing, - out _id, out _key, out _template, out _sortOrder, out _name, - out _urlName, out _creatorId, out _writerId, out _docTypeAlias, out _docTypeId, out _path, - out _createDate, out _updateDate, out _level, out _isDraft, out _contentType, out _properties, - _contentTypeCache.Get); - - _nodeInitialized = true; - } - - // internal for some benchmarks - internal static void InitializeNode(XmlPublishedContent node, XmlNode xmlNode, bool isPreviewing, - out int id, out Guid key, out int template, out int sortOrder, out string name, out string urlName, - out int creatorId, out int writerId, out string docTypeAlias, out int docTypeId, out string path, - out DateTime createDate, out DateTime updateDate, out int level, out bool isDraft, - out IPublishedContentType contentType, out Dictionary properties, - Func getPublishedContentType) - { - //initialize the out params with defaults: - docTypeAlias = null; - id = template = sortOrder = template = creatorId = writerId = docTypeId = level = default(int); - key = default(Guid); - name = docTypeAlias = urlName = path = null; - createDate = updateDate = default(DateTime); - isDraft = false; - contentType = null; - properties = null; - - if (xmlNode == null) return; - - if (xmlNode.Attributes != null) - { - id = int.Parse(xmlNode.Attributes.GetNamedItem("id").Value); - if (xmlNode.Attributes.GetNamedItem("key") != null) // because, migration - key = Guid.Parse(xmlNode.Attributes.GetNamedItem("key").Value); - if (xmlNode.Attributes.GetNamedItem("template") != null) - template = int.Parse(xmlNode.Attributes.GetNamedItem("template").Value); - if (xmlNode.Attributes.GetNamedItem("sortOrder") != null) - sortOrder = int.Parse(xmlNode.Attributes.GetNamedItem("sortOrder").Value); - if (xmlNode.Attributes.GetNamedItem("nodeName") != null) - name = xmlNode.Attributes.GetNamedItem("nodeName").Value; - if (xmlNode.Attributes.GetNamedItem("urlName") != null) - urlName = xmlNode.Attributes.GetNamedItem("urlName").Value; - - //Added the actual userID, as a user cannot be looked up via full name only... - if (xmlNode.Attributes.GetNamedItem("creatorID") != null) - creatorId = int.Parse(xmlNode.Attributes.GetNamedItem("creatorID").Value); - if (xmlNode.Attributes.GetNamedItem("writerID") != null) - writerId = int.Parse(xmlNode.Attributes.GetNamedItem("writerID").Value); - - docTypeAlias = xmlNode.Name; - - if (xmlNode.Attributes.GetNamedItem("nodeType") != null) - docTypeId = int.Parse(xmlNode.Attributes.GetNamedItem("nodeType").Value); - if (xmlNode.Attributes.GetNamedItem("path") != null) - path = xmlNode.Attributes.GetNamedItem("path").Value; - if (xmlNode.Attributes.GetNamedItem("createDate") != null) - createDate = DateTime.Parse(xmlNode.Attributes.GetNamedItem("createDate").Value); - if (xmlNode.Attributes.GetNamedItem("updateDate") != null) - updateDate = DateTime.Parse(xmlNode.Attributes.GetNamedItem("updateDate").Value); - if (xmlNode.Attributes.GetNamedItem("level") != null) - level = int.Parse(xmlNode.Attributes.GetNamedItem("level").Value); - - isDraft = xmlNode.Attributes.GetNamedItem("isDraft") != null; - } - - //dictionary to store the property node data - var propertyNodes = new Dictionary(); - - foreach (XmlNode n in xmlNode.ChildNodes) - { - var e = n as XmlElement; - if (e == null) continue; - if (e.HasAttribute("isDoc") == false) - { - PopulatePropertyNodes(propertyNodes, e, false); - } - else break; //we are not longer on property elements - } - - //lookup the content type and create the properties collection - try - { - contentType = getPublishedContentType(PublishedItemType.Content, docTypeAlias); - - } - catch (InvalidOperationException e) - { - // TODO: enable! - //content.Instance.RefreshContentFromDatabase(); - throw new InvalidOperationException($"{e.Message}. This usually indicates that the content cache is corrupt; the content cache has been rebuilt in an attempt to self-fix the issue."); - } - - //fill in the property collection - properties = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (var propertyType in contentType.PropertyTypes) - { - var val = propertyNodes.TryGetValue(propertyType.Alias.ToLowerInvariant(), out XmlNode n) - ? new XmlPublishedProperty(propertyType, node, isPreviewing, n) - : new XmlPublishedProperty(propertyType, node, isPreviewing); - - properties[propertyType.Alias] = val; - } - } - - private static void PopulatePropertyNodes(IDictionary propertyNodes, XmlNode n, bool legacy) - { - var attrs = n.Attributes; - if (attrs == null) return; - - var alias = legacy - ? attrs.GetNamedItem("alias").Value - : n.Name; - propertyNodes[alias.ToLowerInvariant()] = n; - } - - private void InitializeChildren() - { - if (_xmlNode == null) return; - - // load children - const string childXPath = "* [@isDoc]"; - var nav = _xmlNode.CreateNavigator(); - var expr = nav.Compile(childXPath); - //expr.AddSort("@sortOrder", XmlSortOrder.Ascending, XmlCaseOrder.None, "", XmlDataType.Number); - var iterator = nav.Select(expr); - - _children = iterator.Cast() - .Select(n => Get(((IHasXmlNode) n).GetNode(), _isPreviewing, _appCache, _contentTypeCache, _variationContextAccessor)) - .OrderBy(x => x.SortOrder) - .ToList(); - - _childrenInitialized = true; - } - - /// - /// Gets an IPublishedContent corresponding to an Xml cache node. - /// - /// The Xml node. - /// A value indicating whether we are previewing or not. - /// A cache. - /// A content type cache. - /// A umbraco context accessor - /// - /// The IPublishedContent corresponding to the Xml cache node. - /// Maintains a per-request cache of IPublishedContent items in order to make - /// sure that we create only one instance of each for the duration of a request. The - /// returned IPublishedContent is a model, if models are enabled. - public static IPublishedContent Get(XmlNode node, bool isPreviewing, IAppCache appCache, - PublishedContentTypeCache contentTypeCache, IVariationContextAccessor variationContextAccessor) - { - // only 1 per request - - var attrs = node.Attributes; - var id = attrs?.GetNamedItem("id").Value; - if (id.IsNullOrWhiteSpace()) throw new InvalidOperationException("Node has no ID attribute."); - var key = CacheKeyPrefix + id; // dont bother with preview, wont change during request in Xml cache - return (IPublishedContent) appCache.Get(key, () => (new XmlPublishedContent(node, isPreviewing, appCache, contentTypeCache, variationContextAccessor)).CreateModel(Current.PublishedModelFactory)); - } - - private const string CacheKeyPrefix = "CONTENTCACHE_XMLPUBLISHEDCONTENT_"; - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedProperty.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedProperty.cs deleted file mode 100644 index d0e71e782951..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedProperty.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.Xml; -using System.Xml.Serialization; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.Xml; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - /// - /// Represents an IDocumentProperty which is created based on an Xml structure. - /// - [Serializable] - [XmlType(Namespace = "http://umbraco.org/webservices/")] - internal class XmlPublishedProperty : PublishedPropertyBase - { - private readonly string _sourceValue; // the raw, xml node value - - // Xml cache not using XPath value... and as for the rest... - // we're single threaded here, keep it simple - private object _objectValue; - private bool _objectValueComputed; - private readonly bool _isPreviewing; - private readonly IPublishedContent _content; - - /// - /// Gets the raw value of the property. - /// - public override object GetSourceValue(string culture = null, string segment = null) => _sourceValue; - - // in the Xml cache, everything is a string, and to have a value - // you want to have a non-null, non-empty string. - public override bool HasValue(string culture = null, string segment = null) => _sourceValue.Trim().Length > 0; - - public override object GetValue(string culture = null, string segment = null) - { - // NOT caching the source (intermediate) value since we'll never need it - // everything in Xml cache is per-request anyways - // also, properties should not be shared between requests and therefore - // are single threaded, so the following code should be safe & fast - - if (_objectValueComputed) return _objectValue; - var inter = PropertyType.ConvertSourceToInter(_content, _sourceValue, _isPreviewing); - // initial reference cache level always is .Content - _objectValue = PropertyType.ConvertInterToObject(_content, PropertyCacheLevel.Element, inter, _isPreviewing); - _objectValueComputed = true; - return _objectValue; - } - - public override object GetXPathValue(string culture = null, string segment = null) { throw new NotImplementedException(); } - - public XmlPublishedProperty(IPublishedPropertyType propertyType, IPublishedContent content, bool isPreviewing, XmlNode propertyXmlData) - : this(propertyType, content, isPreviewing) - { - if (propertyXmlData == null) - throw new ArgumentNullException(nameof(propertyXmlData), "Property xml source is null"); - _sourceValue = XmlHelper.GetNodeValue(propertyXmlData); - } - - public XmlPublishedProperty(IPublishedPropertyType propertyType, IPublishedContent content, bool isPreviewing, string propertyData) - : this(propertyType, content, isPreviewing) - { - if (propertyData == null) - throw new ArgumentNullException(nameof(propertyData)); - _sourceValue = propertyData; - } - - public XmlPublishedProperty(IPublishedPropertyType propertyType, IPublishedContent content, bool isPreviewing) - : base(propertyType, PropertyCacheLevel.Unknown) // cache level is ignored - { - _sourceValue = string.Empty; - _content = content; - _isPreviewing = isPreviewing; - } - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs deleted file mode 100644 index 580a4078f8fd..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs +++ /dev/null @@ -1,222 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Persistence.Repositories; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Runtime; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Core.Web; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - /// - /// Implements a published snapshot service. - /// - internal class XmlPublishedSnapshotService : IPublishedSnapshotService - { - private readonly XmlStore _xmlStore; - private readonly RoutesCache _routesCache; - private readonly IPublishedContentTypeFactory _publishedContentTypeFactory; - private readonly PublishedContentTypeCache _contentTypeCache; - private readonly IDomainService _domainService; - private readonly IMediaService _mediaService; - private readonly IUserService _userService; - private readonly IAppCache _requestCache; - private readonly GlobalSettings _globalSettings; - private readonly IDefaultCultureAccessor _defaultCultureAccessor; - private readonly IEntityXmlSerializer _entitySerializer; - private readonly IVariationContextAccessor _variationContextAccessor; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; - - #region Constructors - - // used in WebBootManager + tests - public XmlPublishedSnapshotService( - ServiceContext serviceContext, - IPublishedContentTypeFactory publishedContentTypeFactory, - IScopeProvider scopeProvider, - IAppCache requestCache, - IPublishedSnapshotAccessor publishedSnapshotAccessor, - IVariationContextAccessor variationContextAccessor, - IUmbracoContextAccessor umbracoContextAccessor, - IDocumentRepository documentRepository, - IMediaRepository mediaRepository, - IMemberRepository memberRepository, - IDefaultCultureAccessor defaultCultureAccessor, - ILoggerFactory loggerFactory, - GlobalSettings globalSettings, - IHostingEnvironment hostingEnvironment, - IApplicationShutdownRegistry hostingLifetime, - IShortStringHelper shortStringHelper, - IEntityXmlSerializer entitySerializer, - MainDom mainDom, - bool testing = false, - bool enableRepositoryEvents = true) - : this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache, - publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor, - documentRepository, mediaRepository, memberRepository, - defaultCultureAccessor, - loggerFactory, globalSettings, hostingEnvironment, hostingLifetime, shortStringHelper, entitySerializer, null, mainDom, testing, enableRepositoryEvents) - { - _umbracoContextAccessor = umbracoContextAccessor; - } - - // used in some tests - internal XmlPublishedSnapshotService( - ServiceContext serviceContext, - IPublishedContentTypeFactory publishedContentTypeFactory, - IScopeProvider scopeProvider, - IAppCache requestCache, - IPublishedSnapshotAccessor publishedSnapshotAccessor, - IVariationContextAccessor variationContextAccessor, - IUmbracoContextAccessor umbracoContextAccessor, - IDocumentRepository documentRepository, - IMediaRepository mediaRepository, - IMemberRepository memberRepository, - IDefaultCultureAccessor defaultCultureAccessor, - ILoggerFactory loggerFactory, - GlobalSettings globalSettings, - IHostingEnvironment hostingEnvironment, - IApplicationShutdownRegistry hostingLifetime, - IShortStringHelper shortStringHelper, - IEntityXmlSerializer entitySerializer, - PublishedContentTypeCache contentTypeCache, - MainDom mainDom, - bool testing, - bool enableRepositoryEvents) - { - _routesCache = new RoutesCache(); - _publishedContentTypeFactory = publishedContentTypeFactory; - _contentTypeCache = contentTypeCache - ?? new PublishedContentTypeCache(serviceContext.ContentTypeService, serviceContext.MediaTypeService, serviceContext.MemberTypeService, publishedContentTypeFactory, loggerFactory.CreateLogger()); - - _xmlStore = new XmlStore(serviceContext.ContentTypeService, serviceContext.ContentService, scopeProvider, _routesCache, - _contentTypeCache, publishedSnapshotAccessor, mainDom, testing, enableRepositoryEvents, - documentRepository, mediaRepository, memberRepository, entitySerializer, hostingEnvironment, hostingLifetime, shortStringHelper); - - _domainService = serviceContext.DomainService; - _mediaService = serviceContext.MediaService; - _userService = serviceContext.UserService; - _defaultCultureAccessor = defaultCultureAccessor; - _variationContextAccessor = variationContextAccessor; - _requestCache = requestCache; - _umbracoContextAccessor = umbracoContextAccessor; - _globalSettings = globalSettings; - _entitySerializer = entitySerializer; - } - - public void Dispose() - { - _xmlStore.Dispose(); - } - - #endregion - - public IPublishedSnapshot CreatePublishedSnapshot(string previewToken) - { - // use _requestCache to store recursive properties lookup, etc. both in content - // and media cache. Life span should be the current request. Or, ideally - // the current caches, but that would mean creating an extra cache (StaticCache - // probably) so better use RequestCache. - - var domainCache = new DomainCache(_domainService, _defaultCultureAccessor); - - return new PublishedSnapshot( - new PublishedContentCache(_xmlStore, domainCache, _requestCache, _globalSettings, _contentTypeCache, _routesCache, _variationContextAccessor, previewToken), - new PublishedMediaCache(_xmlStore, _mediaService, _userService, _requestCache, _contentTypeCache, _entitySerializer, _umbracoContextAccessor, _variationContextAccessor), - new PublishedMemberCache(_contentTypeCache, _variationContextAccessor), - domainCache); - } - - #region Xml specific - - /// - /// Gets the underlying XML store. - /// - public XmlStore XmlStore => _xmlStore; - - /// - /// Gets the underlying RoutesCache. - /// - public RoutesCache RoutesCache => _routesCache; - - public bool VerifyContentAndPreviewXml() - { - return XmlStore.VerifyContentAndPreviewXml(); - } - - public void RebuildContentAndPreviewXml() - { - XmlStore.RebuildContentAndPreviewXml(); - } - - public bool VerifyMediaXml() - { - return XmlStore.VerifyMediaXml(); - } - - public void RebuildMediaXml() - { - XmlStore.RebuildMediaXml(); - } - - public bool VerifyMemberXml() - { - return XmlStore.VerifyMemberXml(); - } - - public void RebuildMemberXml() - { - XmlStore.RebuildMemberXml(); - } - - #endregion - - #region Change management - - public void Notify(ContentCacheRefresher.JsonPayload[] payloads, out bool draftChanged, out bool publishedChanged) - { - _xmlStore.Notify(payloads, out draftChanged, out publishedChanged); - } - - public void Notify(MediaCacheRefresher.JsonPayload[] payloads, out bool anythingChanged) - { - foreach (var payload in payloads) - PublishedMediaCache.ClearCache(payload.Id); - - anythingChanged = true; - } - - public void Notify(ContentTypeCacheRefresher.JsonPayload[] payloads) - { - _xmlStore.Notify(payloads); - if (payloads.Any(x => x.ItemType == typeof(IContentType).Name)) - _routesCache.Clear(); - } - - public void Notify(DataTypeCacheRefresher.JsonPayload[] payloads) - { - _publishedContentTypeFactory.NotifyDataTypeChanges(payloads.Select(x => x.Id).ToArray()); - _xmlStore.Notify(payloads); - } - - public void Notify(DomainCacheRefresher.JsonPayload[] payloads) - { - _routesCache.Clear(); - } - - #endregion - - public void Rebuild(int groupSize = 5000, IReadOnlyCollection contentTypeIds = null, IReadOnlyCollection mediaTypeIds = null, IReadOnlyCollection memberTypeIds = null) { } - - public Task CollectAsync() => Task.CompletedTask; - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs deleted file mode 100644 index af0848010d50..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs +++ /dev/null @@ -1,2058 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -using Microsoft.Extensions.Logging; -using Moq; -using NPoco; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Cms.Core.Persistence.Repositories; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Runtime; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Services.Changes; -using Umbraco.Cms.Core.Services.Implement; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Core.Xml; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -using Umbraco.Extensions; -using Umbraco.Tests.TestHelpers; -using Umbraco.Web.Composing; -using Umbraco.Web.Scheduling; -using File = System.IO.File; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - /// - /// Represents the Xml storage for the Xml published cache. - /// - /// - /// One instance of is instantiated by the and - /// then passed to all instances that are created (one per request). - /// This class should *not* be public. - /// - internal class XmlStore : - IDisposable, - INotificationHandler, - INotificationHandler, - INotificationHandler, - INotificationHandler, - INotificationHandler, - INotificationHandler, - INotificationHandler, - INotificationHandler, - INotificationHandler, - INotificationHandler, - INotificationHandler - { - private readonly IDocumentRepository _documentRepository; - private readonly IMediaRepository _mediaRepository; - private readonly IMemberRepository _memberRepository; - private readonly IEntityXmlSerializer _entitySerializer; - private readonly IApplicationShutdownRegistry _hostingLifetime; - private readonly IShortStringHelper _shortStringHelper; - private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; - private readonly PublishedContentTypeCache _contentTypeCache; - private readonly RoutesCache _routesCache; - private readonly IContentTypeService _contentTypeService; - private readonly IContentService _contentService; - private readonly IScopeProvider _scopeProvider; - - private XmlStoreFilePersister _persisterTask; - private volatile bool _released; - - #region Constructors - - /// - /// Initializes a new instance of the class. - /// - /// The default constructor will boot the cache, load data from file or database, /// wire events in order to manage changes, etc. - public XmlStore(IContentTypeService contentTypeService, IContentService contentService, IScopeProvider scopeProvider, RoutesCache routesCache, PublishedContentTypeCache contentTypeCache, - IPublishedSnapshotAccessor publishedSnapshotAccessor, MainDom mainDom, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IEntityXmlSerializer entitySerializer, IHostingEnvironment hostingEnvironment, IApplicationShutdownRegistry hostingLifetime, IShortStringHelper shortStringHelper) - : this(contentTypeService, contentService, scopeProvider, routesCache, contentTypeCache, publishedSnapshotAccessor, mainDom, false, false, documentRepository, mediaRepository, memberRepository, entitySerializer, hostingEnvironment, hostingLifetime, shortStringHelper) - { } - - // internal for unit tests - // no file nor db, no config check - // TODO: er, we DO have a DB? - internal XmlStore(IContentTypeService contentTypeService, IContentService contentService, IScopeProvider scopeProvider, RoutesCache routesCache, PublishedContentTypeCache contentTypeCache, - IPublishedSnapshotAccessor publishedSnapshotAccessor, MainDom mainDom, - bool testing, bool enableRepositoryEvents, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IEntityXmlSerializer entitySerializer, IHostingEnvironment hostingEnvironment, IApplicationShutdownRegistry hostingLifetime, IShortStringHelper shortStringHelper) - { - if (testing == false) - EnsureConfigurationIsValid(); - - _contentTypeService = contentTypeService; - _contentService = contentService; - _scopeProvider = scopeProvider; - _routesCache = routesCache; - _contentTypeCache = contentTypeCache; - _publishedSnapshotAccessor = publishedSnapshotAccessor; - _documentRepository = documentRepository; - _mediaRepository = mediaRepository; - _memberRepository = memberRepository; - _entitySerializer = entitySerializer; - _hostingLifetime = hostingLifetime; - _shortStringHelper = shortStringHelper; - - _xmlFileName = TestHelper.IOHelper.MapPath(SystemFiles.GetContentCacheXml(hostingEnvironment)); - - if (testing) - { - _xmlFileEnabled = false; - } - else - { - InitializeFilePersister(mainDom); - } - - Initialize(testing, enableRepositoryEvents); - } - - // internal for unit tests - // initialize with an xml document - // no events, no file nor db, no config check - internal XmlStore(XmlDocument xmlDocument, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IHostingEnvironment hostingEnvironment) - { - _xmlDocument = xmlDocument; - _documentRepository = documentRepository; - _mediaRepository = mediaRepository; - _memberRepository = memberRepository; - _xmlFileEnabled = false; - _xmlFileName = TestHelper.IOHelper.MapPath(SystemFiles.GetContentCacheXml(hostingEnvironment)); - // do not plug events, we may not have what it takes to handle them - } - - // internal for unit tests - // initialize with a function returning an xml document - // no events, no file nor db, no config check - internal XmlStore(Func getXmlDocument, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IHostingEnvironment hostingEnvironment) - { - _documentRepository = documentRepository; - _mediaRepository = mediaRepository; - _memberRepository = memberRepository; - GetXmlDocument = getXmlDocument ?? throw new ArgumentNullException(nameof(getXmlDocument)); - _xmlFileEnabled = false; - _xmlFileName = TestHelper.IOHelper.MapPath(SystemFiles.GetContentCacheXml(hostingEnvironment)); - // do not plug events, we may not have what it takes to handle them - } - - private void InitializeFilePersister(MainDom mainDom) - { - if (SyncToXmlFile == false) return; - - var loggerFactory = Current.LoggerFactory; - - // there's always be one task keeping a ref to the runner - // so it's safe to just create it as a local var here - var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions - { - LongRunning = true, - KeepAlive = true, - Hosted = false // main domain will take care of stopping the runner (see below) - }, loggerFactory.CreateLogger>(), _hostingLifetime); - - // create (and add to runner) - _persisterTask = new XmlStoreFilePersister(runner, this, loggerFactory.CreateLogger()); - - var registered = mainDom.Register( - null, - () => - { - // once released, the cache still works but does not write to file anymore, - // which is OK with database server messenger but will cause data loss with - // another messenger... - - runner.Shutdown(false, true); // wait until flushed - _persisterTask = null; // fail fast - _released = true; - }); - - // failed to become the main domain, we will never use the file - if (registered == false) - runner.Shutdown(false, true); - - _released = registered == false; - } - - private void Initialize(bool testing, bool enableRepositoryEvents) - { - - // not so soon! if eg installing we may not be able to load content yet - // so replace this by LazyInitializeContent() called in Xml ppty getter - //InitializeContent(); - } - - private void LazyInitializeContent() - { - if (_xml != null) return; - - // and populate the cache - using (var safeXml = GetSafeXmlWriter()) - { - if (_xml != null) return; // double-check - - // if we don't use the file then LoadXmlLocked will not even - // read from the file and will go straight to database - LoadXmlLocked(safeXml, out bool registerXmlChange); - - // if we use the file and registerXmlChange is true this will - // write to file, else it will not - safeXml.AcceptChanges(registerXmlChange); - } - } - - public void Dispose() - { - } - - #endregion - - #region Configuration - - // gathering configuration options here to document what they mean - - private readonly bool _xmlFileEnabled = true; - - // whether the disk cache is enabled - private bool XmlFileEnabled => true; - - // whether the disk cache is enabled and to update the disk cache when xml changes - private bool SyncToXmlFile => true; - - // whether the disk cache is enabled and to reload from disk cache if it changes - private bool SyncFromXmlFile => false; - - // whether _xml is immutable or not (achieved by cloning before changing anything) - private static bool XmlIsImmutable => true; - - // whether to keep version of everything (incl. medias & members) in cmsPreviewXml - // for audit purposes - false by default, not in umbracoSettings.config - // whether to... no idea what that one does - // it is false by default and not in UmbracoSettings.config anymore - ignoring - /* - private static bool GlobalPreviewStorageEnabled - { - get { return UmbracoConfig.For.UmbracoSettings().Content.GlobalPreviewStorageEnabled; } - } - */ - - // ensures config is valid - private void EnsureConfigurationIsValid() - { - if (SyncToXmlFile && SyncFromXmlFile) - throw new Exception("Cannot run with both ContinouslyUpdateXmlDiskCache and XmlContentCheckForDiskChanges being true."); - - if (XmlIsImmutable == false) - //Current.Logger.LogWarning("Running with CloneXmlContent being false is a bad idea."); - Current.Logger.LogWarning("CloneXmlContent is false - ignored, we always clone."); - - // note: if SyncFromXmlFile then we should also disable / warn that local edits are going to cause issues... - } - - #endregion - - #region Xml - - /// - /// Gets or sets the delegate used to retrieve the Xml content, used for unit tests, else should - /// be null and then the default content will be used. For non-preview content only. - /// - /// - /// The default content ONLY works when in the context an Http Request mostly because the - /// 'content' object heavily relies on HttpContext, SQL connections and a bunch of other stuff - /// that when run inside of a unit test fails. - /// - public Func GetXmlDocument { get; set; } - - private XmlDocument _xmlDocument; // supplied xml document (for tests) - private volatile XmlDocument _xml; // master xml document - private readonly SystemLock _xmlLock = new SystemLock(); // protects _xml - - // to be used by PublishedContentCache only - // for non-preview content only - public XmlDocument Xml - { - get - { - if (_xml != null) - return _xml; - - if (_xmlDocument != null) - { - _xml = _xmlDocument; - _xmlDocument = null; - return _xml; - } - - if (GetXmlDocument != null) - return _xml = GetXmlDocument(); - - LazyInitializeContent(); - ReloadXmlFromFileIfChanged(); - return _xml; - } - } - - // Gets the temp. Xml managed by SafeXmlReaderWrite, if any - public XmlDocument TempXml => SafeXmlReaderWriter.Get(_scopeProvider)?.Xml; - - // assumes xml lock - private void SetXmlLocked(XmlDocument xml, bool registerXmlChange) - { - // this is the ONLY place where we write to _xml - _xml = xml; - - _routesCache?.Clear(); // anytime we set _xml - - if (registerXmlChange == false || SyncToXmlFile == false) - return; - - _persisterTask = _persisterTask?.Touch(); - } - - private static XmlDocument EnsureSchema(string contentTypeAlias, XmlDocument xml) - { - string subset = null; - - // get current doctype - var n = xml.FirstChild; - while (n.NodeType != XmlNodeType.DocumentType && n.NextSibling != null) - n = n.NextSibling; - if (n.NodeType == XmlNodeType.DocumentType) - subset = ((XmlDocumentType)n).InternalSubset; - - // ensure it contains the content type - if (subset != null && subset.Contains($"")) - return xml; - - // alas, that does not work, replacing a doctype is ignored and GetElementById fails - // - //// remove current doctype, set new doctype - //xml.RemoveChild(n); - //subset = string.Format("{0}{0}{2}", Environment.NewLine, contentTypeAlias, subset); - //var doctype = xml.CreateDocumentType("root", null, null, subset); - //xml.InsertAfter(doctype, xml.FirstChild); - - var xml2 = new XmlDocument(); - subset = string.Format("{0}{0}{2}", Environment.NewLine, contentTypeAlias, subset); - var doctype = xml2.CreateDocumentType("root", null, null, subset); - xml2.AppendChild(doctype); - xml2.AppendChild(xml2.ImportNode(xml.DocumentElement, true)); - return xml2; - } - - private static void InitializeXml(XmlDocument xml, string dtd) - { - // prime the xml document with an inline dtd and a root element - xml.LoadXml(string.Format("{0}{1}{0}", Environment.NewLine, dtd)); - } - - /// - /// Generates the complete (simplified) XML DTD. - /// - /// The DTD as a string - private string GetDtd() - { - var dtd = new StringBuilder(); - dtd.AppendLine(" x.Alias.ToSafeAlias(_shortStringHelper)).WhereNotNull(); - foreach (var alias in aliases) - { - dtdInner.AppendLine($""); - dtdInner.AppendLine($""); - } - dtd.Append(dtdInner); - } - catch (Exception ex) - { - Current.Logger.LogError(ex, "Failed to build a DTD for the Xml cache."); - } - - dtd.AppendLine("]>"); - return dtd.ToString(); - } - - // try to load from file, otherwise database - // assumes xml lock (file is always locked) - private void LoadXmlLocked(SafeXmlReaderWriter safeXml, out bool registerXmlChange) - { - Current.Logger.LogDebug("Loading Xml..."); - - // try to get it from the file - if (XmlFileEnabled && (safeXml.Xml = LoadXmlFromFile()) != null) - { - registerXmlChange = false; // loaded from disk, do NOT write back to disk! - return; - } - - // get it from the database, and register - LoadXmlTreeFromDatabaseLocked(safeXml); - registerXmlChange = true; - } - - public XmlNode GetMediaXmlNode(int mediaId) - { - // there's only one version for medias - - const string sql = @"SELECT umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, umbracoNode.Level, -cmsContentXml.xml, 1 AS published -FROM umbracoNode -JOIN cmsContentXml ON (cmsContentXml.nodeId=umbracoNode.id) -WHERE umbracoNode.nodeObjectType = @nodeObjectType -AND (umbracoNode.id=@id)"; - - XmlDto xmlDto; - using (var scope = _scopeProvider.CreateScope()) - { - scope.ReadLock(Constants.Locks.MediaTree); - var xmlDtos = scope.Database.Query(sql, - new - { - nodeObjectType = Constants.ObjectTypes.Media, - id = mediaId - }); - xmlDto = xmlDtos.FirstOrDefault(); - scope.Complete(); - } - - if (xmlDto == null) return null; - - var doc = new XmlDocument(); - var xml = doc.ReadNode(XmlReader.Create(new StringReader(xmlDto.Xml))); - return xml; - } - - public XmlNode GetMemberXmlNode(int memberId) - { - // there's only one version for members - - const string sql = @"SELECT umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, umbracoNode.Level, -cmsContentXml.xml, 1 AS published -FROM umbracoNode -JOIN cmsContentXml ON (cmsContentXml.nodeId=umbracoNode.id) -WHERE umbracoNode.nodeObjectType = @nodeObjectType -AND (umbracoNode.id=@id)"; - - XmlDto xmlDto; - using (var scope = _scopeProvider.CreateScope()) - { - scope.ReadLock(Constants.Locks.MemberTree); - var xmlDtos = scope.Database.Query(sql, - new - { - nodeObjectType = Constants.ObjectTypes.Member, - id = memberId - }); - xmlDto = xmlDtos.FirstOrDefault(); - scope.Complete(); - } - - if (xmlDto == null) return null; - - var doc = new XmlDocument(); - var xml = doc.ReadNode(XmlReader.Create(new StringReader(xmlDto.Xml))); - return xml; - } - - private static readonly string PreviewXmlNodeSql = $@"SELECT umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, umbracoNode.Level, -cmsPreviewXml.xml, {Constants.DatabaseSchema.Tables.Document}.published -FROM umbracoNode -JOIN cmsPreviewXml ON (cmsPreviewXml.nodeId=umbracoNode.id) -JOIN {Constants.DatabaseSchema.Tables.Document} ON ({Constants.DatabaseSchema.Tables.Document}.nodeId=umbracoNode.id) -WHERE umbracoNode.nodeObjectType = @nodeObjectType -AND (umbracoNode.id=@id)"; - - public XmlNode GetPreviewXmlNode(int contentId) - { - var sql = PreviewXmlNodeSql; - - XmlDto xmlDto; - using (var scope = _scopeProvider.CreateScope()) - { - scope.ReadLock(Constants.Locks.ContentTree); - var xmlDtos = scope.Database.Query(sql, - new - { - nodeObjectType = Constants.ObjectTypes.Document, - id = contentId - }); - xmlDto = xmlDtos.FirstOrDefault(); - scope.Complete(); - } - if (xmlDto == null) return null; - - var doc = new XmlDocument(); - var xml = doc.ReadNode(XmlReader.Create(new StringReader(xmlDto.Xml))); - if (xml?.Attributes == null) return null; - - if (xmlDto.Published == false) - xml.Attributes.Append(doc.CreateAttribute("isDraft")); - return xml; - } - - public XmlDocument GetMediaXml() - { - // this is not efficient at all, not cached, nothing - // just here to replicate what uQuery was doing and show it can be done - // but really - should not be used - - return LoadMoreXmlFromDatabase(Constants.ObjectTypes.Media); - } - - public XmlDocument GetMemberXml() - { - // this is not efficient at all, not cached, nothing - // just here to replicate what uQuery was doing and show it can be done - // but really - should not be used - - return LoadMoreXmlFromDatabase(Constants.ObjectTypes.Member); - } - - public XmlDocument GetPreviewXml(int contentId, bool includeSubs) - { - var content = _contentService.GetById(contentId); - - var doc = (XmlDocument)Xml.Clone(); - if (content == null) return doc; - - using (var scope = _scopeProvider.CreateScope()) - { - scope.ReadLock(Constants.Locks.ContentTree); - var sqlSyntax = scope.SqlContext.SqlSyntax; - - var sql = ReadCmsPreviewXmlSql1; - sql += " @path LIKE " + sqlSyntax.GetConcat("umbracoNode.Path", "',%"); // concat(umbracoNode.path, ',%') - if (includeSubs) sql += " OR umbracoNode.path LIKE " + sqlSyntax.GetConcat("@path", "',%"); // concat(@path, ',%') - sql += ReadCmsPreviewXmlSql2; - - var xmlDtos = scope.Database.Query(sql, - new - { - nodeObjectType = Constants.ObjectTypes.Document, - path = content.Path, - }); - - foreach (var xmlDto in xmlDtos) - { - var xml = xmlDto.XmlNode = doc.ReadNode(XmlReader.Create(new StringReader(xmlDto.Xml))); - if (xml?.Attributes == null) continue; - if (xmlDto.Published == false) - xml.Attributes.Append(doc.CreateAttribute("isDraft")); - doc = AddOrUpdateXmlNode(doc, xmlDto); - } - - scope.Complete(); - } - - return doc; - } - - // NOTE - // - this is NOT a reader/writer lock and each lock is exclusive - // - these locks are NOT reentrant / recursive - // - // should we have async versions that would do: ? - // var releaser = await _xmlLock.LockAsync(); - // - // TODO: not sure about the "resync current published snapshot" thing here, see 7.6... - - // gets a locked safe read access to the main xml - private SafeXmlReaderWriter GetSafeXmlReader() - { - return SafeXmlReaderWriter.Get(_scopeProvider, _xmlLock, _xml, - ResyncCurrentPublishedSnapshot, - (xml, registerXmlChange) => - { - SetXmlLocked(xml, registerXmlChange); - ResyncCurrentPublishedSnapshot(xml); - }, false); - } - - // gets a locked safe write access to the main xml (cloned) - private SafeXmlReaderWriter GetSafeXmlWriter() - { - return SafeXmlReaderWriter.Get(_scopeProvider, _xmlLock, _xml, - ResyncCurrentPublishedSnapshot, - (xml, registerXmlChange) => - { - SetXmlLocked(xml, registerXmlChange); - ResyncCurrentPublishedSnapshot(xml); - }, true); - } - - private const string ChildNodesXPath = "./* [@id]"; - private const string DataNodesXPath = "./* [not(@id)]"; - - #endregion - - #region File - - private readonly string _xmlFileName; - private DateTime _lastFileRead; // last time the file was read - private DateTime _nextFileCheck; // last time we checked whether the file was changed - - public void EnsureFilePermission() - { - // TODO: but do we really have a store, initialized, at that point? - var filename = _xmlFileName + ".temp"; - File.WriteAllText(filename, "TEMP"); - File.Delete(filename); - } - - // not used - just try to read the file - //private bool XmlFileExists - //{ - // get - // { - // // check that the file exists and has content (is not empty) - // var fileInfo = new FileInfo(_xmlFileName); - // return fileInfo.Exists && fileInfo.Length > 0; - // } - //} - - private DateTime XmlFileLastWriteTime - { - get - { - var fileInfo = new FileInfo(_xmlFileName); - return fileInfo.Exists ? fileInfo.LastWriteTimeUtc : DateTime.MinValue; - } - } - - // invoked by XmlStoreFilePersister ONLY and that one manages the MainDom, ie it - // will NOT try to save once the current app domain is not the main domain anymore - // (no need to test _released) - internal void SaveXmlToFile() - { - Current.Logger.LogInformation("Save Xml to file..."); - - try - { - var xml = _xml; // capture (atomic + volatile), immutable anyway - if (xml == null) return; - - // delete existing file, if any - DeleteXmlFile(); - - // ensure cache directory exists - var directoryName = Path.GetDirectoryName(_xmlFileName); - if (directoryName == null) - throw new Exception($"Invalid XmlFileName \"{_xmlFileName}\"."); - if (File.Exists(_xmlFileName) == false && Directory.Exists(directoryName) == false) - Directory.CreateDirectory(directoryName); - - // save - using (var fs = new FileStream(_xmlFileName, FileMode.Create, FileAccess.Write, FileShare.Read, bufferSize: 4096, useAsync: true)) - { - var bytes = Encoding.UTF8.GetBytes(SaveXmlToString(xml)); - fs.Write(bytes, 0, bytes.Length); - } - - Current.Logger.LogInformation("Saved Xml to file."); - } - catch (Exception ex) - { - // if something goes wrong remove the file - DeleteXmlFile(); - - Current.Logger.LogError(ex, "Failed to save Xml to file '{FileName}'.", _xmlFileName); - } - } - - // invoked by XmlStoreFilePersister ONLY and that one manages the MainDom, ie it - // will NOT try to save once the current app domain is not the main domain anymore - // (no need to test _released) - internal async Task SaveXmlToFileAsync() - { - Current.Logger.LogInformation("Save Xml to file..."); - - try - { - var xml = _xml; // capture (atomic + volatile), immutable anyway - if (xml == null) return; - - // delete existing file, if any - DeleteXmlFile(); - - // ensure cache directory exists - var directoryName = Path.GetDirectoryName(_xmlFileName); - if (directoryName == null) - throw new Exception($"Invalid XmlFileName \"{_xmlFileName}\"."); - if (File.Exists(_xmlFileName) == false && Directory.Exists(directoryName) == false) - Directory.CreateDirectory(directoryName); - - // save - using (var fs = new FileStream(_xmlFileName, FileMode.Create, FileAccess.Write, FileShare.Read, bufferSize: 4096, useAsync: true)) - { - var bytes = Encoding.UTF8.GetBytes(SaveXmlToString(xml)); - await fs.WriteAsync(bytes, 0, bytes.Length); - } - - Current.Logger.LogInformation("Saved Xml to file."); - } - catch (Exception ex) - { - // if something goes wrong remove the file - DeleteXmlFile(); - - Current.Logger.LogError(ex, "Failed to save Xml to file '{FileName}'.", _xmlFileName); - } - } - - private static string SaveXmlToString(XmlDocument xml) - { - // using that one method because we want to have proper indent - // and in addition, writing async is never fully async because - // although the writer is async, xml.WriteTo() will not async - - // that one almost works but... "The elements are indented as long as the element - // does not contain mixed content. Once the WriteString or WriteWhitespace method - // is called to write out a mixed element content, the XmlWriter stops indenting. - // The indenting resumes once the mixed content element is closed." - says MSDN - // about XmlWriterSettings.Indent - - // so ImportContentBase must also make sure of ignoring whitespaces! - - var sb = new StringBuilder(); - using (var xmlWriter = XmlWriter.Create(sb, new XmlWriterSettings - { - Indent = true, - Encoding = Encoding.UTF8, - //OmitXmlDeclaration = true - })) - { - //xmlWriter.WriteProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""); - xml.WriteTo(xmlWriter); // already contains the xml declaration - } - return sb.ToString(); - } - - private XmlDocument LoadXmlFromFile() - { - // do NOT try to load if we are not the main domain anymore - if (_released) return null; - - Current.Logger.LogInformation("Load Xml from file..."); - - try - { - var xml = new XmlDocument(); - using (var fs = new FileStream(_xmlFileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - xml.Load(fs); - } - _lastFileRead = DateTime.UtcNow; - Current.Logger.LogInformation("Loaded Xml from file."); - return xml; - } - catch (FileNotFoundException) - { - Current.Logger.LogWarning("Failed to load Xml, file does not exist."); - return null; - } - catch (Exception ex) - { - Current.Logger.LogError(ex, "Failed to load Xml from file '{FileName}'.", _xmlFileName); - try - { - DeleteXmlFile(); - } - catch - { - // don't make it worse: could be that we failed to read because we cannot - // access the file, in which case we won't be able to delete it either - } - return null; - } - } - - private void DeleteXmlFile() - { - if (File.Exists(_xmlFileName) == false) return; - File.SetAttributes(_xmlFileName, FileAttributes.Normal); - File.Delete(_xmlFileName); - } - - private void ReloadXmlFromFileIfChanged() - { - if (SyncFromXmlFile == false) return; - - var now = DateTime.UtcNow; - if (now < _nextFileCheck) return; - - // time to check - _nextFileCheck = now.AddSeconds(1); // check every 1s - if (XmlFileLastWriteTime <= _lastFileRead) return; - - Current.Logger.LogDebug("Xml file change detected, reloading."); - - // time to read - - using (var safeXml = GetSafeXmlWriter()) - { - LoadXmlLocked(safeXml, out bool registerXmlChange); // updates _lastFileRead - safeXml.AcceptChanges(registerXmlChange); - } - } - - #endregion - - #region Database - - private static readonly string ReadTreeCmsContentXmlSql = $@"SELECT - umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, umbracoNode.level, umbracoNode.path, - cmsContentXml.xml, cmsContentXml.rv, {Constants.DatabaseSchema.Tables.Document}.published -FROM umbracoNode -JOIN cmsContentXml ON (cmsContentXml.nodeId=umbracoNode.id) -JOIN {Constants.DatabaseSchema.Tables.Document} ON ({Constants.DatabaseSchema.Tables.Document}.nodeId=umbracoNode.id) -WHERE umbracoNode.nodeObjectType = @nodeObjectType AND {Constants.DatabaseSchema.Tables.Document}.published=1 -ORDER BY umbracoNode.level, umbracoNode.sortOrder"; - - private static readonly string ReadBranchCmsContentXmlSql = $@"SELECT - umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, umbracoNode.level, umbracoNode.path, - cmsContentXml.xml, cmsContentXml.rv, {Constants.DatabaseSchema.Tables.Document}.published -FROM umbracoNode -JOIN cmsContentXml ON (cmsContentXml.nodeId=umbracoNode.id) -JOIN {Constants.DatabaseSchema.Tables.Document} ON ({Constants.DatabaseSchema.Tables.Document}.nodeId=umbracoNode.id) -WHERE umbracoNode.nodeObjectType = @nodeObjectType AND {Constants.DatabaseSchema.Tables.Document}.published=1 AND (umbracoNode.id = @id OR umbracoNode.path LIKE @path) -ORDER BY umbracoNode.level, umbracoNode.sortOrder"; - - private static readonly string ReadCmsContentXmlForContentTypesSql = $@"SELECT - umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, umbracoNode.level, umbracoNode.path, - cmsContentXml.xml, cmsContentXml.rv, {Constants.DatabaseSchema.Tables.Document}.published -FROM umbracoNode -JOIN cmsContentXml ON (cmsContentXml.nodeId=umbracoNode.id) -JOIN {Constants.DatabaseSchema.Tables.Document} ON ({Constants.DatabaseSchema.Tables.Document}.nodeId=umbracoNode.id) -JOIN {Constants.DatabaseSchema.Tables.Content} ON ({Constants.DatabaseSchema.Tables.Document}.nodeId={Constants.DatabaseSchema.Tables.Content}.nodeId) -WHERE umbracoNode.nodeObjectType = @nodeObjectType AND {Constants.DatabaseSchema.Tables.Document}.published=1 AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ids) -ORDER BY umbracoNode.level, umbracoNode.sortOrder"; - - private const string ReadMoreCmsContentXmlSql = @"SELECT - umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, umbracoNode.level, umbracoNode.path, - cmsContentXml.xml, cmsContentXml.rv, 1 AS published -FROM umbracoNode -JOIN cmsContentXml ON (cmsContentXml.nodeId=umbracoNode.id) -WHERE umbracoNode.nodeObjectType = @nodeObjectType -ORDER BY umbracoNode.level, umbracoNode.sortOrder"; - - private static readonly string ReadCmsPreviewXmlSql1 = $@"SELECT - umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, umbracoNode.level, umbracoNode.path, - cmsPreviewXml.xml, cmsPreviewXml.rv, {Constants.DatabaseSchema.Tables.Document}.published -FROM umbracoNode -JOIN cmsPreviewXml ON (cmsPreviewXml.nodeId=umbracoNode.id) -JOIN {Constants.DatabaseSchema.Tables.Document} ON ({Constants.DatabaseSchema.Tables.Document}.nodeId=umbracoNode.id) -WHERE umbracoNode.nodeObjectType = @nodeObjectType AND {Constants.DatabaseSchema.Tables.Document}.published=1 -AND (umbracoNode.path=@path OR"; // @path LIKE concat(umbracoNode.path, ',%')"; - - private const string ReadCmsPreviewXmlSql2 = @") -ORDER BY umbracoNode.level, umbracoNode.sortOrder"; - - // ReSharper disable once ClassNeverInstantiated.Local - private class XmlDto - { - // ReSharper disable UnusedAutoPropertyAccessor.Local - - public int Id { get; set; } - public long Rv { get; set; } - public int ParentId { get; set; } - //public int SortOrder { get; set; } - public int Level { get; set; } - public string Path { get; set; } - public string Xml { get; set; } - public bool Published { get; set; } - - [Ignore] - public XmlNode XmlNode { get; set; } - - // ReSharper restore UnusedAutoPropertyAccessor.Local - } - - // assumes xml lock - private void LoadXmlTreeFromDatabaseLocked(SafeXmlReaderWriter safeXml) - { - // initialize the document ready for the composition of content - var xml = new XmlDocument(); - InitializeXml(xml, GetDtd()); - - XmlNode parent = null; - var parentId = 0; - - using (var scope = _scopeProvider.CreateScope()) - { - scope.ReadLock(Constants.Locks.ContentTree); - - // get xml - var xmlDtos = scope.Database.Query(ReadTreeCmsContentXmlSql, - new { nodeObjectType = Constants.ObjectTypes.Document }); - - foreach (var xmlDto in xmlDtos) - { - xmlDto.XmlNode = ImportContent(xml, xmlDto); // parse into a DOM node - - if (parent == null || parentId != xmlDto.ParentId) - { - parent = xmlDto.ParentId == -1 - ? xml.DocumentElement - : xml.GetElementById(xmlDto.ParentId.ToInvariantString()); - - if (parent == null) continue; - - parentId = xmlDto.ParentId; - } - - parent.AppendChild(xmlDto.XmlNode); - } - - scope.Complete(); - } - - safeXml.Xml = xml; - } - - private XmlDocument LoadMoreXmlFromDatabase(Guid nodeObjectType) - { - var xmlDoc = new XmlDocument(); - - using (var scope = _scopeProvider.CreateScope()) - { - if (nodeObjectType == Constants.ObjectTypes.Document) - scope.ReadLock(Constants.Locks.ContentTree); - else if (nodeObjectType == Constants.ObjectTypes.Media) - scope.ReadLock(Constants.Locks.MediaTree); - else if (nodeObjectType == Constants.ObjectTypes.Member) - scope.ReadLock(Constants.Locks.MemberTree); - - var xmlDtos = scope.Database.Query(ReadMoreCmsContentXmlSql, - new { /*@nodeObjectType =*/ nodeObjectType }); - - // Initialize the document ready for the final composition of content - InitializeXml(xmlDoc, string.Empty); - - XmlNode parent = null; - var parentId = 0; - - foreach (var xmlDto in xmlDtos) - { - // and parse it into a DOM node - var node = xmlDoc.ReadNode(XmlReader.Create(new StringReader(xmlDto.Xml), new XmlReaderSettings - { - IgnoreWhitespace = true - })); - - if (parent == null || parentId != xmlDto.ParentId) - { - parent = xmlDto.ParentId == -1 - ? xmlDoc.DocumentElement - : xmlDoc.GetElementById(xmlDto.ParentId.ToInvariantString()); - - if (parent == null) - continue; - - parentId = xmlDto.ParentId; - } - - parent.AppendChild(node); - } - - scope.Complete(); - } - - return xmlDoc; - } - - // internal - used by umbraco.content.RefreshContentFromDatabase[Async] - internal void ReloadXmlFromDatabase() - { - // event - cancel - - // nobody should work on the Xml while we load - using (var safeXml = GetSafeXmlWriter()) - { - LoadXmlTreeFromDatabaseLocked(safeXml); - safeXml.AcceptChanges(); - } - } - - #endregion - - #region Handle Distributed Notifications for Memory Xml - - // NOT using events, see notes in IPublishedCachesService - - public void Notify(ContentCacheRefresher.JsonPayload[] payloads, out bool draftChanged, out bool publishedChanged) - { - draftChanged = publishedChanged = false; - if (_xml == null) return; // not initialized yet! - - draftChanged = true; // by default - we don't track drafts - publishedChanged = false; - - // process all changes on one xml clone - using (var safeXml = GetSafeXmlWriter()) - { - foreach (var payload in payloads) - { - Current.Logger.LogDebug("Notified {ChangeTypes} for content {ContentId}", payload.ChangeTypes, payload.Id); - - if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshAll)) - { - LoadXmlTreeFromDatabaseLocked(safeXml); - publishedChanged = true; - continue; - } - - if (payload.ChangeTypes.HasType(TreeChangeTypes.Remove)) - { - var toRemove = safeXml.Xml.GetElementById(payload.Id.ToInvariantString()); - if (toRemove != null) - { - if (toRemove.ParentNode == null) throw new Exception("oops"); - toRemove.ParentNode.RemoveChild(toRemove); - publishedChanged = true; - } - continue; - } - - if (payload.ChangeTypes.HasTypesNone(TreeChangeTypes.RefreshNode | TreeChangeTypes.RefreshBranch)) - { - // ?! - continue; - } - - var content = _contentService.GetById(payload.Id); - var current = safeXml.Xml.GetElementById(payload.Id.ToInvariantString()); - - if (content == null || content.Published == false || content.Trashed) - { - // no published version - Current.Logger.LogDebug("Notified, content {ContentId} has no published version.", payload.Id); - - if (current != null) - { - // remove from xml if exists - if (current.ParentNode == null) throw new Exception("oops"); - current.ParentNode.RemoveChild(current); - publishedChanged = true; - } - - continue; - } - - // else we have a published version - - // get xml - using (var scope = _scopeProvider.CreateScope()) - { - scope.ReadLock(Constants.Locks.ContentTree); - - // that query is yielding results so will only load what's needed - var xmlDtos = scope.Database.Query(ReadBranchCmsContentXmlSql, - new - { - nodeObjectType = Constants.ObjectTypes.Document, - path = content.Path + ",%", - id = content.Id - }); - - // 'using' the enumerator ensures that the enumeration is properly terminated even if abandoned - // otherwise, it would leak an open reader & an un-released database connection - // see PetaPoco.Query(Type[] types, Delegate cb, string sql, params object[] args) - // and read http://blogs.msdn.com/b/oldnewthing/archive/2008/08/14/8862242.aspx - // - using (var dtos = xmlDtos.GetEnumerator()) - { - if (dtos.MoveNext() == false) - { - // gone fishing, remove (possible race condition) - Current.Logger.LogDebug("Notified, content {ContentId} gone fishing.", payload.Id); - - if (current != null) - { - // remove from xml if exists - if (current.ParentNode == null) throw new Exception("oops"); - current.ParentNode.RemoveChild(current); - publishedChanged = true; - } - continue; - } - - if (dtos.Current.Id != content.Id) - throw new Exception("oops"); // first one should be 'current' - var currentDto = dtos.Current; - - // note: if anything eg parentId or path or level has changed, then rv has changed too - var currentRv = current == null ? -1 : int.Parse(current.Attributes["rv"].Value); - - // if exists and unchanged and not refreshing the branch, skip entirely - if (current != null - && currentRv == currentDto.Rv - && payload.ChangeTypes.HasType(TreeChangeTypes.RefreshBranch) == false) - continue; - - currentDto.XmlNode = ImportContent(safeXml.Xml, currentDto); - - // note: Examine would not be able to do the path trick below, and we cannot help for - // unpublished content, so it *is* possible that Examine is inconsistent for a while, - // though events should get it consistent eventually. - - // note: if path has changed we must do a branch refresh, even if the event is not requiring - // it, otherwise we would update the local node and not its children, who would then have - // inconsistent level (and path) attributes. - - var refreshBranch = current == null - || payload.ChangeTypes.HasType(TreeChangeTypes.RefreshBranch) - || current.Attributes["path"].Value != currentDto.Path; - - if (refreshBranch) - { - // remove node if exists - if (current != null) - { - if (current.ParentNode == null) throw new Exception("oops"); - current.ParentNode.RemoveChild(current); - } - - // insert node - var newParent = currentDto.ParentId == -1 - ? safeXml.Xml.DocumentElement - : safeXml.Xml.GetElementById(currentDto.ParentId.ToInvariantString()); - if (newParent == null) continue; - newParent.AppendChild(currentDto.XmlNode); - XmlHelper.SortNode(newParent, ChildNodesXPath, currentDto.XmlNode, - x => x.AttributeValue("sortOrder")); - - // add branch (don't try to be clever) - while (dtos.MoveNext()) - { - // dtos are ordered by sortOrder already - var dto = dtos.Current; - - // if node is already there, somewhere, remove - var n = safeXml.Xml.GetElementById(dto.Id.ToInvariantString()); - if (n != null) - { - if (n.ParentNode == null) throw new Exception("oops"); - n.ParentNode.RemoveChild(n); - } - - // find parent, add node - var p = safeXml.Xml.GetElementById(dto.ParentId.ToInvariantString()); // branch, so parentId > 0 - // takes care of out-of-sync & masked - p?.AppendChild(dto.XmlNode); - } - } - else - { - // in-place - safeXml.Xml = AddOrUpdateXmlNode(safeXml.Xml, currentDto); - } - } - - scope.Complete(); - } - - publishedChanged = true; - } - - if (publishedChanged) - safeXml.AcceptChanges(); - } - } - - public void Notify(ContentTypeCacheRefresher.JsonPayload[] payloads) - { - if (_xml == null) return; // not initialized yet! - - // see ContentTypeServiceBase - // in all cases we just want to clear the content type cache - // the type will be reloaded if/when needed - foreach (var payload in payloads) - _contentTypeCache.ClearContentType(payload.Id); - - // process content types / content cache - // only those that have been changed - with impact on content - RefreshMain - // for those that have been removed, content is removed already - var ids = payloads - .Where(x => x.ItemType == typeof(IContentType).Name && x.ChangeTypes.HasType(ContentTypeChangeTypes.RefreshMain)) - .Select(x => x.Id) - .ToArray(); - - foreach (var payload in payloads) - Current.Logger.LogDebug("Notified {ChangeTypes} for content type {ContentTypeId}", payload.ChangeTypes, payload.Id); - - if (ids.Length > 0) // must have refreshes, not only removes - RefreshContentTypes(ids); - - // ignore media and member types - we're not caching them - } - - public void Notify(DataTypeCacheRefresher.JsonPayload[] payloads) - { - if (_xml == null) return; // not initialized yet! - - // see above - // in all cases we just want to clear the content type cache - // the types will be reloaded if/when needed - foreach (var payload in payloads) - _contentTypeCache.ClearDataType(payload.Id); - - foreach (var payload in payloads) - Current.Logger.LogDebug("Notified {RemovedStatus} for data type {payload.Id}", - payload.Removed ? "Removed" : "Refreshed", - payload.Id); - - // that's all we need to do as the changes have NO impact whatsoever on the Xml content - - // ignore media and member types - we're not caching them - } - - private void ResyncCurrentPublishedSnapshot(XmlDocument xml) - { - var publishedSnapshot = (PublishedSnapshot) _publishedSnapshotAccessor.PublishedSnapshot; - if (publishedSnapshot == null) return; - ((PublishedContentCache) publishedSnapshot.Content).Resync(xml); - ((PublishedMediaCache) publishedSnapshot.Media).Resync(); - - // not trying to resync members or domains, which are not cached really - } - - #endregion - - #region Manage change - - private void RefreshContentTypes(IEnumerable ids) - { - using (var safeXml = GetSafeXmlWriter()) - using (var scope = _scopeProvider.CreateScope()) - { - scope.ReadLock(Constants.Locks.ContentTree); - var xmlDtos = scope.Database.Query(ReadCmsContentXmlForContentTypesSql, - new { nodeObjectType = Constants.ObjectTypes.Document, /*@ids =*/ ids }); - - foreach (var xmlDto in xmlDtos) - { - xmlDto.XmlNode = safeXml.Xml.ReadNode(XmlReader.Create(new StringReader(xmlDto.Xml))); - safeXml.Xml = AddOrUpdateXmlNode(safeXml.Xml, xmlDto); - } - - scope.Complete(); - safeXml.AcceptChanges(); - } - } - - // nothing to do, we have no cache - //private void RefreshMediaTypes(IEnumerable ids) - //{ } - - // nothing to do, we have no cache - //private void RefreshMemberTypes(IEnumerable ids) - //{ } - - // adds or updates a node (docNode) into a cache (xml) - private static XmlDocument AddOrUpdateXmlNode(XmlDocument xml, XmlDto xmlDto) - { - // sanity checks - var docNode = xmlDto.XmlNode; - if (xmlDto.Id != docNode.AttributeValue("id")) - throw new ArgumentException("Values of id and docNode/@id are different."); - if (xmlDto.ParentId != docNode.AttributeValue("parentID")) - throw new ArgumentException("Values of parentId and docNode/@parentID are different."); - - // find the document in the cache - XmlNode currentNode = xml.GetElementById(xmlDto.Id.ToInvariantString()); - - // if the document is not there already then it's a new document - // we must make sure that its document type exists in the schema - if (currentNode == null) - { - var xml2 = EnsureSchema(docNode.Name, xml); - if (ReferenceEquals(xml, xml2) == false) - docNode = xml2.ImportNode(docNode, true); - xml = xml2; - } - - // find the parent - XmlNode parentNode = xmlDto.Level == 1 - ? xml.DocumentElement - : xml.GetElementById(xmlDto.ParentId.ToInvariantString()); - - // no parent = cannot do anything - if (parentNode == null) - return xml; - - // insert/move the node under the parent - if (currentNode == null) - { - // document not there, new node, append - currentNode = docNode; - parentNode.AppendChild(currentNode); - } - else - { - // document found... we could just copy the currentNode children nodes over under - // docNode, then remove currentNode and insert docNode... the code below tries to - // be clever and faster, though only benchmarking could tell whether it's worth the - // pain... - - // first copy current parent ID - so we can compare with target parent - var moving = currentNode.AttributeValue("parentID") != xmlDto.ParentId; - - if (docNode.Name == currentNode.Name) - { - // name has not changed, safe to just update the current node - // by transferring values eg copying the attributes, and importing the data elements - TransferValuesFromDocumentXmlToPublishedXml(docNode, currentNode); - - // if moving, move the node to the new parent - // else it's already under the right parent - // (but maybe the sort order has been updated) - if (moving) - parentNode.AppendChild(currentNode); // remove then append to parentNode - } - else - { - // name has changed, must use docNode (with new name) - // move children nodes from currentNode to docNode (already has properties) - var children = currentNode.SelectNodes(ChildNodesXPath); - if (children == null) throw new Exception("oops"); - foreach (XmlNode child in children) - docNode.AppendChild(child); // remove then append to docNode - - // and put docNode in the right place - if parent has not changed, then - // just replace, else remove currentNode and insert docNode under the right parent - // (but maybe not at the right position due to sort order) - if (moving) - { - if (currentNode.ParentNode == null) throw new Exception("oops"); - currentNode.ParentNode.RemoveChild(currentNode); - parentNode.AppendChild(docNode); - } - else - { - // replacing might screw the sort order - parentNode.ReplaceChild(docNode, currentNode); - } - - currentNode = docNode; - } - } - - var attrs = currentNode.Attributes; - if (attrs == null) throw new Exception("oops."); - - var attr = attrs["rv"] ?? attrs.Append(xml.CreateAttribute("rv")); - attr.Value = xmlDto.Rv.ToString(CultureInfo.InvariantCulture); - - attr = attrs["path"] ?? attrs.Append(xml.CreateAttribute("path")); - attr.Value = xmlDto.Path; - - // if the nodes are not ordered, must sort - // (see U4-509 + has to work with ReplaceChild too) - //XmlHelper.SortNodesIfNeeded(parentNode, childNodesXPath, x => x.AttributeValue("sortOrder")); - - // but... - // if we assume that nodes are always correctly sorted - // then we just need to ensure that currentNode is at the right position. - // should be faster that moving all the nodes around. - XmlHelper.SortNode(parentNode, ChildNodesXPath, currentNode, x => x.AttributeValue("sortOrder")); - return xml; - } - - private static void TransferValuesFromDocumentXmlToPublishedXml(XmlNode documentNode, XmlNode publishedNode) - { - // remove all attributes from the published node - if (publishedNode.Attributes == null) throw new Exception("oops"); - publishedNode.Attributes.RemoveAll(); - - // remove all data nodes from the published node - var dataNodes = publishedNode.SelectNodes(DataNodesXPath); - if (dataNodes == null) throw new Exception("oops"); - foreach (XmlNode n in dataNodes) - publishedNode.RemoveChild(n); - - // append all attributes from the document node to the published node - if (documentNode.Attributes == null) throw new Exception("oops"); - foreach (XmlAttribute att in documentNode.Attributes) - ((XmlElement)publishedNode).SetAttribute(att.Name, att.Value); - - // find the first child node, if any - var childNodes = publishedNode.SelectNodes(ChildNodesXPath); - if (childNodes == null) throw new Exception("oops"); - var firstChildNode = childNodes.Count == 0 ? null : childNodes[0]; - - // append all data nodes from the document node to the published node - dataNodes = documentNode.SelectNodes(DataNodesXPath); - if (dataNodes == null) throw new Exception("oops"); - foreach (XmlNode n in dataNodes) - { - if (publishedNode.OwnerDocument == null) throw new Exception("oops"); - var imported = publishedNode.OwnerDocument.ImportNode(n, true); - if (firstChildNode == null) - publishedNode.AppendChild(imported); - else - publishedNode.InsertBefore(imported, firstChildNode); - } - } - - private static XmlNode ImportContent(XmlDocument xml, XmlDto dto) - { - var node = xml.ReadNode(XmlReader.Create(new StringReader(dto.Xml), new XmlReaderSettings - { - IgnoreWhitespace = true - })); - - if (node == null) throw new Exception("oops"); - if (node.Attributes == null) throw new Exception("oops"); - - var attr = xml.CreateAttribute("rv"); - attr.Value = dto.Rv.ToString(CultureInfo.InvariantCulture); - node.Attributes.Append(attr); - - attr = xml.CreateAttribute("path"); - attr.Value = dto.Path; - node.Attributes.Append(attr); - - return node; - } - - #endregion - - #region Handle Repository Events For Database Xml - - // we need them to be "repository" events ie to trigger from within the repository transaction, - // because they need to be consistent with the content that is being refreshed/removed - and that - // should be guaranteed by a DB transaction - // it is not the case at the moment, instead a global lock is used whenever content is modified - well, - // almost: rollback or unpublish do not implement it - nevertheless - - public void Handle(ContentDeletingNotification notification) - { - foreach (IContent entity in notification.DeletedEntities) - { - // We used to do args.Scope.Database, but can't any more because it's not supported by the notification pattern - OnRemovedEntity(null, entity); - } - } - - public void Handle(MediaDeletingNotification notification) - { - foreach (IMedia entity in notification.DeletedEntities) - { - // We used to do args.Scope.Database, but can't any more because it's not supported by the notification pattern - OnRemovedEntity(null, entity); - } - } - - public void Handle(MemberDeletingNotification notification) - { - foreach (IMember entity in notification.DeletedEntities) - { - // We used to do args.Scope.Database, but can't any more because it's not supported by the notification pattern - OnRemovedEntity(null, entity); - } - } - - private static void OnRemovedEntity(IUmbracoDatabase db, IContentBase item) - { - var parms = new { id = item.Id }; - db.Execute("DELETE FROM cmsContentXml WHERE nodeId=@id", parms); - db.Execute("DELETE FROM cmsPreviewXml WHERE nodeId=@id", parms); - - // note: could be optimized by using "WHERE nodeId IN (...)" delete clauses - } - - public void Handle(ContentDeletingVersionsNotification notification) - { - OnRemovedVersion(null, notification.Id, notification.SpecificVersion); - } - - public void Handle(MediaDeletingVersionsNotification notification) - { - OnRemovedVersion(null, notification.Id, notification.SpecificVersion); - } - - private static void OnRemovedVersion(IUmbracoDatabase db, int entityId, int versionId) - { - // we do not version cmsPreviewXml anymore - nothing to do here - } - - private static readonly string[] PropertiesImpactingAllVersions = { "SortOrder", "ParentId", "Level", "Path", "Trashed" }; - - private static bool HasChangesImpactingAllVersions(IContent icontent) - { - var content = (Content)icontent; - - // UpdateDate will be dirty - // Published may be dirty if saving a Published entity - // so cannot do this (would always be true): - //return content.IsEntityDirty(); - - // have to be more precise & specify properties - return PropertiesImpactingAllVersions.Any(content.IsPropertyDirty); - } - - public void Handle(ContentRefreshNotification notification) - { - var db = Mock.Of(); // Notification no longer carries the scope, so we can't get the DB - var entity = notification.Entity; - - // serialize edit values for preview - var editXml = _entitySerializer.Serialize(entity, false).ToDataString(); - - // change below to write only one row - not one per version - var dto1 = new PreviewXmlDto - { - NodeId = entity.Id, - Xml = editXml - }; - OnRepositoryRefreshed(db, dto1); - - // if unpublishing, remove from table - - if (((Content) entity).PublishedState == PublishedState.Unpublishing) - { - db.Execute("DELETE FROM cmsContentXml WHERE nodeId=@id", new { id = entity.Id }); - return; - } - - // need to update the published xml if we're saving the published version, - // or having an impact on that version - we update the published xml even when masked - - // TODO: in the repo... either its 'unpublished' and 'publishing', or 'published' and 'published', this has changed! - // TODO: what are we serializing really? which properties? - - // if not publishing, no change to published xml - if (((Content) entity).PublishedState != PublishedState.Publishing) - return; - - // serialize published values for content cache - var publishedXml = _entitySerializer.Serialize(entity, true).ToDataString(); - var dto2 = new ContentXmlDto { NodeId = entity.Id, Xml = publishedXml }; - OnRepositoryRefreshed(db, dto2); - - } - - public void Handle(MediaRefreshNotification notification) - { - var db = Mock.Of(); // Notification no longer carries the scope, so we can't get the DB - var entity = notification.Entity; - - // for whatever reason we delete some xml when the media is trashed - // at least that's what the MediaService implementation did - if (entity.Trashed) - db.Execute("DELETE FROM cmsContentXml WHERE nodeId=@id", new { id = entity.Id }); - - var xml = _entitySerializer.Serialize(entity).ToDataString(); - - var dto1 = new ContentXmlDto { NodeId = entity.Id, Xml = xml }; - OnRepositoryRefreshed(db, dto1); - } - - public void Handle(MemberRefreshNotification notification) - { - var db = Mock.Of(); // Notification no longer carries the scope, so we can't get the DB - var entity = notification.Entity; - - var xml = _entitySerializer.Serialize(entity).ToDataString(); - - var dto1 = new ContentXmlDto { NodeId = entity.Id, Xml = xml }; - OnRepositoryRefreshed(db, dto1); - } - - private static void OnRepositoryRefreshed(IUmbracoDatabase db, ContentXmlDto dto) - { - // use a custom SQL to update row version on each update - //db.InsertOrUpdate(dto); - - db.InsertOrUpdate(dto, - "SET xml=@xml, rv=rv+1 WHERE nodeId=@id", - new - { - xml = dto.Xml, - id = dto.NodeId - }); - } - - private static void OnRepositoryRefreshed(IUmbracoDatabase db, PreviewXmlDto dto) - { - // cannot simply update because of PetaPoco handling of the composite key ;-( - // read http://stackoverflow.com/questions/11169144/how-to-modify-petapoco-class-to-work-with-composite-key-comprising-of-non-numeri - // it works in https://github.com/schotime/PetaPoco and then https://github.com/schotime/NPoco but not here - // - // not important anymore as we don't manage version anymore, - // but: - // - // also - // use a custom SQL to update row version on each update - //db.InsertOrUpdate(dto); - - db.InsertOrUpdate(dto, - "SET xml=@xml, rv=rv+1 WHERE nodeId=@id", - new - { - xml = dto.Xml, - id = dto.NodeId, - }); - } - - public void Handle(ContentTypeRefreshedNotification notification) - { - const ContentTypeChangeTypes types // only for those that have been refreshed - = ContentTypeChangeTypes.RefreshMain | ContentTypeChangeTypes.RefreshOther | ContentTypeChangeTypes.Create; - var contentTypeIds = notification.Changes.Where(x => x.ChangeTypes.HasTypesAny(types)).Select(x => x.Item.Id).ToArray(); - if (contentTypeIds.Any()) - RebuildContentAndPreviewXml(contentTypeIds: contentTypeIds); - } - - public void Handle(MediaTypeRefreshedNotification notification) - { - const ContentTypeChangeTypes types // only for those that have been refreshed - = ContentTypeChangeTypes.RefreshMain | ContentTypeChangeTypes.RefreshOther | ContentTypeChangeTypes.Create; - var mediaTypeIds = notification.Changes.Where(x => x.ChangeTypes.HasTypesAny(types)).Select(x => x.Item.Id).ToArray(); - if (mediaTypeIds.Any()) - { - RebuildMediaXml(contentTypeIds: mediaTypeIds); - } - } - - public void Handle(MemberTypeRefreshedNotification notification) - { - const ContentTypeChangeTypes types // only for those that have been refreshed - = ContentTypeChangeTypes.RefreshMain | ContentTypeChangeTypes.RefreshOther | ContentTypeChangeTypes.Create; - var memberTypeIds = notification.Changes.Where(x => x.ChangeTypes.HasTypesAny(types)).Select(x => x.Item.Id).ToArray(); - if (memberTypeIds.Any()) - RebuildMemberXml(contentTypeIds: memberTypeIds); - } - - #endregion - - #region Rebuild Database Xml - - // RepositoryCacheMode.Scoped because we do NOT want to use the L2 cache that may be out-of-sync - // hopefully this does not cause issues and we're not nested in another scope w/different mode - // TODO: well, guess what? - // original code made sure the repository used no cache - // now we're using the Scoped scope cache mode - // and then? - - public void RebuildContentAndPreviewXml(int groupSize = 5000, IEnumerable contentTypeIds = null) - { - var contentTypeIdsA = contentTypeIds?.ToArray(); - - using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.None)) - { - scope.WriteLock(Constants.Locks.ContentTree); - RebuildContentXmlLocked(scope, groupSize, contentTypeIdsA); - RebuildPreviewXmlLocked(scope, groupSize, contentTypeIdsA); - scope.Complete(); - } - } - - public void RebuildContentXml(int groupSize = 5000, IEnumerable contentTypeIds = null) - { - using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.None)) - { - scope.WriteLock(Constants.Locks.ContentTree); - RebuildContentXmlLocked(scope, groupSize, contentTypeIds); - scope.Complete(); - } - } - - // assumes content tree lock - private void RebuildContentXmlLocked(IScope scope, int groupSize, IEnumerable contentTypeIds) - { - var contentTypeIdsA = contentTypeIds?.ToArray(); - var contentObjectType = Constants.ObjectTypes.Document; - var db = scope.Database; - - // remove all - if anything fails the transaction will rollback - if (contentTypeIds == null || contentTypeIdsA.Length == 0) - { - // must support SQL-CE - // db.Execute(@"DELETE cmsContentXml - //FROM cmsContentXml - //JOIN umbracoNode ON (cmsContentXml.nodeId=umbracoNode.Id) - //WHERE umbracoNode.nodeObjectType=@objType", - db.Execute(@"DELETE FROM cmsContentXml -WHERE cmsContentXml.nodeId IN ( - SELECT id FROM umbracoNode WHERE umbracoNode.nodeObjectType=@objType -)", - new { objType = contentObjectType }); - } - else - { - // assume number of ctypes won't blow IN(...) - // must support SQL-CE - // db.Execute(@"DELETE cmsContentXml - //FROM cmsContentXml - //JOIN umbracoNode ON (cmsContentXml.nodeId=umbracoNode.Id) - //JOIN {Constants.DatabaseSchema.Tables.Content} ON (cmsContentXml.nodeId={Constants.DatabaseSchema.Tables.Content}.nodeId) - //WHERE umbracoNode.nodeObjectType=@objType - //AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes)", - db.Execute($@"DELETE FROM cmsContentXml -WHERE cmsContentXml.nodeId IN ( - SELECT id FROM umbracoNode - JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id - WHERE umbracoNode.nodeObjectType=@objType - AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) -)", - new { objType = contentObjectType, ctypes = contentTypeIdsA }); - } - - // insert back - if anything fails the transaction will rollback - var query = scope.SqlContext.Query().Where(x => x.Published); - if (contentTypeIds != null && contentTypeIdsA.Length > 0) - query = query.WhereIn(x => x.ContentTypeId, contentTypeIdsA); // assume number of ctypes won't blow IN(...) - - long pageIndex = 0; - long processed = 0; - long total; - do - { - var descendants = _documentRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path")); - const bool published = true; // contentXml contains published content! - var items = descendants.Select(c => new ContentXmlDto { NodeId = c.Id, Xml = - _entitySerializer.Serialize(c, published).ToDataString() }).ToArray(); - db.BulkInsertRecords(items); - processed += items.Length; - } while (processed < total); - } - - public void RebuildPreviewXml(int groupSize = 5000, IEnumerable contentTypeIds = null) - { - using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.None)) - { - scope.WriteLock(Constants.Locks.ContentTree); - RebuildPreviewXmlLocked(scope, groupSize, contentTypeIds); - scope.Complete(); - scope.Complete(); - } - } - - // assumes content tree lock - private void RebuildPreviewXmlLocked(IScope scope, int groupSize, IEnumerable contentTypeIds) - { - var contentTypeIdsA = contentTypeIds?.ToArray(); - var contentObjectType = Constants.ObjectTypes.Document; - var db = scope.Database; - - // remove all - if anything fails the transaction will rollback - if (contentTypeIds == null || contentTypeIdsA.Length == 0) - { - // must support SQL-CE - // db.Execute(@"DELETE cmsPreviewXml - //FROM cmsPreviewXml - //JOIN umbracoNode ON (cmsPreviewXml.nodeId=umbracoNode.Id) - //WHERE umbracoNode.nodeObjectType=@objType", - db.Execute(@"DELETE FROM cmsPreviewXml -WHERE cmsPreviewXml.nodeId IN ( - SELECT id FROM umbracoNode WHERE umbracoNode.nodeObjectType=@objType -)", - new { objType = contentObjectType }); - } - else - { - // assume number of ctypes won't blow IN(...) - // must support SQL-CE - // db.Execute(@"DELETE cmsPreviewXml - //FROM cmsPreviewXml - //JOIN umbracoNode ON (cmsPreviewXml.nodeId=umbracoNode.Id) - //JOIN {Constants.DatabaseSchema.Tables.Content} ON (cmsPreviewXml.nodeId={Constants.DatabaseSchema.Tables.Content}.nodeId) - //WHERE umbracoNode.nodeObjectType=@objType - //AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes)", - db.Execute($@"DELETE FROM cmsPreviewXml -WHERE cmsPreviewXml.nodeId IN ( - SELECT id FROM umbracoNode - JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id - WHERE umbracoNode.nodeObjectType=@objType - AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) -)", - new { objType = contentObjectType, ctypes = contentTypeIdsA }); - } - - // insert back - if anything fails the transaction will rollback - var query = scope.SqlContext.Query(); - if (contentTypeIds != null && contentTypeIdsA.Length > 0) - query = query.WhereIn(x => x.ContentTypeId, contentTypeIdsA); // assume number of ctypes won't blow IN(...) - - long pageIndex = 0; - long processed = 0; - long total; - do - { - // .GetPagedResultsByQuery implicitly adds ({Constants.DatabaseSchema.Tables.Document}.newest = 1) which - // is what we want for preview (ie latest version of a content, published or not) - var descendants = _documentRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path")); - const bool published = true; // previewXml contains edit content! - var items = descendants.Select(c => new PreviewXmlDto - { - NodeId = c.Id, - Xml = _entitySerializer.Serialize(c, published).ToDataString() - }).ToArray(); - db.BulkInsertRecords(items); - processed += items.Length; - } while (processed < total); - } - - public void RebuildMediaXml(int groupSize = 5000, IEnumerable contentTypeIds = null) - { - using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.None)) - { - scope.WriteLock(Constants.Locks.MediaTree); - RebuildMediaXmlLocked(scope, groupSize, contentTypeIds); - scope.Complete(); - } - } - - // assumes media tree lock - public void RebuildMediaXmlLocked(IScope scope, int groupSize, IEnumerable contentTypeIds) - { - var contentTypeIdsA = contentTypeIds?.ToArray(); - var mediaObjectType = Constants.ObjectTypes.Media; - var db = scope.Database; - - // remove all - if anything fails the transaction will rollback - if (contentTypeIds == null || contentTypeIdsA.Length == 0) - { - // must support SQL-CE - // db.Execute(@"DELETE cmsContentXml - //FROM cmsContentXml - //JOIN umbracoNode ON (cmsContentXml.nodeId=umbracoNode.Id) - //WHERE umbracoNode.nodeObjectType=@objType", - db.Execute(@"DELETE FROM cmsContentXml -WHERE cmsContentXml.nodeId IN ( - SELECT id FROM umbracoNode WHERE umbracoNode.nodeObjectType=@objType -)", - new { objType = mediaObjectType }); - } - else - { - // assume number of ctypes won't blow IN(...) - // must support SQL-CE - // db.Execute(@"DELETE cmsContentXml - //FROM cmsContentXml - //JOIN umbracoNode ON (cmsContentXml.nodeId=umbracoNode.Id) - //JOIN {Constants.DatabaseSchema.Tables.Content} ON (cmsContentXml.nodeId={Constants.DatabaseSchema.Tables.Content}.nodeId) - //WHERE umbracoNode.nodeObjectType=@objType - //AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes)", - db.Execute($@"DELETE FROM cmsContentXml -WHERE cmsContentXml.nodeId IN ( - SELECT id FROM umbracoNode - JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id - WHERE umbracoNode.nodeObjectType=@objType - AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) -)", - new { objType = mediaObjectType, ctypes = contentTypeIdsA }); - } - - // insert back - if anything fails the transaction will rollback - var query = scope.SqlContext.Query(); - if (contentTypeIds != null && contentTypeIdsA.Length > 0) - query = query.WhereIn(x => x.ContentTypeId, contentTypeIdsA); // assume number of ctypes won't blow IN(...) - - long pageIndex = 0; - long processed = 0; - long total; - do - { - var descendants = _mediaRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path")); - var items = descendants.Select(m => new ContentXmlDto { NodeId = m.Id, Xml = - _entitySerializer.Serialize(m).ToDataString() }).ToArray(); - db.BulkInsertRecords(items); - processed += items.Length; - } while (processed < total); - } - - public void RebuildMemberXml(int groupSize = 5000, IEnumerable contentTypeIds = null) - { - using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.None)) - { - scope.WriteLock(Constants.Locks.MemberTree); - RebuildMemberXmlLocked(scope, groupSize, contentTypeIds); - scope.Complete(); - } - } - - // assumes member tree lock - public void RebuildMemberXmlLocked(IScope scope, int groupSize, IEnumerable contentTypeIds) - { - var contentTypeIdsA = contentTypeIds?.ToArray(); - var memberObjectType = Constants.ObjectTypes.Member; - var db = scope.Database; - - // remove all - if anything fails the transaction will rollback - if (contentTypeIds == null || contentTypeIdsA.Length == 0) - { - // must support SQL-CE - // db.Execute(@"DELETE cmsContentXml - //FROM cmsContentXml - //JOIN umbracoNode ON (cmsContentXml.nodeId=umbracoNode.Id) - //WHERE umbracoNode.nodeObjectType=@objType", - db.Execute(@"DELETE FROM cmsContentXml -WHERE cmsContentXml.nodeId IN ( - SELECT id FROM umbracoNode WHERE umbracoNode.nodeObjectType=@objType -)", - new { objType = memberObjectType }); - } - else - { - // assume number of ctypes won't blow IN(...) - // must support SQL-CE - // db.Execute(@"DELETE cmsContentXml - //FROM cmsContentXml - //JOIN umbracoNode ON (cmsContentXml.nodeId=umbracoNode.Id) - //JOIN {Constants.DatabaseSchema.Tables.Content} ON (cmsContentXml.nodeId={Constants.DatabaseSchema.Tables.Content}.nodeId) - //WHERE umbracoNode.nodeObjectType=@objType - //AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes)", - db.Execute($@"DELETE FROM cmsContentXml -WHERE cmsContentXml.nodeId IN ( - SELECT id FROM umbracoNode - JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id - WHERE umbracoNode.nodeObjectType=@objType - AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) -)", - new { objType = memberObjectType, ctypes = contentTypeIdsA }); - } - - // insert back - if anything fails the transaction will rollback - var query = scope.SqlContext.Query(); - if (contentTypeIds != null && contentTypeIdsA.Length > 0) - query = query.WhereIn(x => x.ContentTypeId, contentTypeIdsA); // assume number of ctypes won't blow IN(...) - - long pageIndex = 0; - long processed = 0; - long total; - do - { - var descendants = _memberRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path")); - var items = descendants.Select(m => new ContentXmlDto { NodeId = m.Id, Xml = _entitySerializer.Serialize(m).ToDataString() }).ToArray(); - db.BulkInsertRecords(items); - processed += items.Length; - } while (processed < total); - } - - public bool VerifyContentAndPreviewXml() - { - using (var scope = _scopeProvider.CreateScope()) - { - scope.ReadLock(Constants.Locks.ContentTree); - var ok = VerifyContentAndPreviewXmlLocked(scope); - scope.Complete(); - return ok; - } - } - - // assumes content tree lock - private static bool VerifyContentAndPreviewXmlLocked(IScope scope) - { - // every published content item should have a corresponding row in cmsContentXml - // every content item should have a corresponding row in cmsPreviewXml - // and that row should have the key="..." attribute - - var contentObjectType = Constants.ObjectTypes.Document; - var db = scope.Database; - - var count = db.ExecuteScalar($@"SELECT COUNT(*) -FROM umbracoNode -JOIN {Constants.DatabaseSchema.Tables.Document} ON (umbracoNode.id={Constants.DatabaseSchema.Tables.Document}.nodeId and {Constants.DatabaseSchema.Tables.Document}.published=1) -LEFT JOIN cmsContentXml ON (umbracoNode.id=cmsContentXml.nodeId) -WHERE umbracoNode.nodeObjectType=@objType -AND cmsContentXml.nodeId IS NULL OR cmsContentXml.xml NOT LIKE '% key=""' -", new { objType = contentObjectType }); - - if (count > 0) return false; - - count = db.ExecuteScalar(@"SELECT COUNT(*) -FROM umbracoNode -LEFT JOIN cmsPreviewXml ON (umbracoNode.id=cmsPreviewXml.nodeId) -WHERE umbracoNode.nodeObjectType=@objType -AND cmsPreviewXml.nodeId IS NULL OR cmsPreviewXml.xml NOT LIKE '% key=""' -", new { objType = contentObjectType }); - - return count == 0; - } - - public bool VerifyMediaXml() - { - using (var scope = _scopeProvider.CreateScope()) - { - scope.ReadLock(Constants.Locks.MediaTree); - var ok = VerifyMediaXmlLocked(scope); - scope.Complete(); - return ok; - } - } - - // assumes media tree lock - public bool VerifyMediaXmlLocked(IScope scope) - { - // every non-trashed media item should have a corresponding row in cmsContentXml - // and that row should have the key="..." attribute - // TODO: where's the trashed test here? - - var mediaObjectType = Constants.ObjectTypes.Media; - var db = scope.Database; - - var count = db.ExecuteScalar($@"SELECT COUNT(*) -FROM umbracoNode -JOIN {Constants.DatabaseSchema.Tables.Document} ON (umbracoNode.id={Constants.DatabaseSchema.Tables.Document}.nodeId and {Constants.DatabaseSchema.Tables.Document}.published=1) -LEFT JOIN cmsContentXml ON (umbracoNode.id=cmsContentXml.nodeId) -WHERE umbracoNode.nodeObjectType=@objType -AND cmsContentXml.nodeId IS NULL OR cmsContentXml.xml NOT LIKE '% key=""' -", new { objType = mediaObjectType }); - - return count == 0; - } - - public bool VerifyMemberXml() - { - using (var scope = _scopeProvider.CreateScope()) - { - scope.ReadLock(Constants.Locks.MemberTree); - var ok = VerifyMemberXmlLocked(scope); - scope.Complete(); - return ok; - } - } - - // assumes member tree lock - public bool VerifyMemberXmlLocked(IScope scope) - { - // every member item should have a corresponding row in cmsContentXml - - var memberObjectType = Constants.ObjectTypes.Member; - var db = scope.Database; - - var count = db.ExecuteScalar(@"SELECT COUNT(*) -FROM umbracoNode -LEFT JOIN cmsContentXml ON (umbracoNode.id=cmsContentXml.nodeId) -WHERE umbracoNode.nodeObjectType=@objType -AND cmsContentXml.nodeId IS NULL -", new { objType = memberObjectType }); - - return count == 0; - } - - #endregion - } -} diff --git a/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlStoreFilePersister.cs b/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlStoreFilePersister.cs deleted file mode 100644 index 6029a069cb99..000000000000 --- a/tests/Umbraco.Tests/LegacyXmlPublishedCache/XmlStoreFilePersister.cs +++ /dev/null @@ -1,181 +0,0 @@ -using System; -using System.Threading; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core; -using Umbraco.Web.Scheduling; - -namespace Umbraco.Tests.LegacyXmlPublishedCache -{ - /// - /// This is the background task runner that persists the xml file to the file system - /// - /// - /// This is used so that all file saving is done on a web aware worker background thread and all logic is performed async so this - /// process will not interfere with any web requests threads. This is also done as to not require any global locks and to ensure that - /// if multiple threads are performing publishing tasks that the file will be persisted in accordance with the final resulting - /// xml structure since the file writes are queued. - /// - internal class XmlStoreFilePersister : LatchedBackgroundTaskBase - { - private readonly IBackgroundTaskRunner _runner; - private readonly ILogger _logger; - private readonly XmlStore _store; - private readonly object _locko = new object(); - private bool _released; - private Timer _timer; - private DateTime _initialTouch; - private readonly SystemLock _runLock = new SystemLock(); // ensure we run once at a time - - // note: - // as long as the runner controls the runs, we know that we run once at a time, but - // when the AppDomain goes down and the runner has completed and yet the persister is - // asked to save, then we need to run immediately - but the runner may be running, so - // we need to make sure there's no collision - hence _runLock - - private const int WaitMilliseconds = 4000; // save the cache 4s after the last change (ie every 4s min) - private const int MaxWaitMilliseconds = 30000; // save the cache after some time (ie no more than 30s of changes) - - // save the cache when the app goes down - public override bool RunsOnShutdown => _timer != null; - - // initialize the first instance, which is inactive (not touched yet) - public XmlStoreFilePersister(IBackgroundTaskRunner runner, XmlStore store, ILogger logger) - : this(runner, store, logger, false) - { } - - // initialize further instances, which are active (touched) - private XmlStoreFilePersister(IBackgroundTaskRunner runner, XmlStore store, ILogger logger, bool touched) - { - _runner = runner; - _store = store; - _logger = logger; - - if (_runner.TryAdd(this) == false) - { - _runner = null; // runner's down - _released = true; // don't mess with timer - return; - } - - // runner could decide to run it anytime now - - if (touched == false) return; - - _logger.LogDebug("Created, save in {WaitMilliseconds}ms.", WaitMilliseconds); - _initialTouch = DateTime.Now; - _timer = new Timer(_ => TimerRelease()); - _timer.Change(WaitMilliseconds, 0); - } - - public XmlStoreFilePersister Touch() - { - // if _released is false then we're going to setup a timer - // then the runner wants to shutdown & run immediately - // this sets _released to true & the timer will trigger eventually & who cares? - // if _released is true, either it's a normal release, or - // a runner shutdown, in which case we won't be able to - // add a new task, and so we'll run immediately - - var ret = this; - var runNow = false; - - lock (_locko) - { - if (_released) // our timer has triggered OR the runner is shutting down - { - _logger.LogDebug("Touched, was released..."); - - // release: has run or is running, too late, return a new task (adds itself to runner) - if (_runner == null) - { - _logger.LogDebug("Runner is down, run now."); - runNow = true; - } - else - { - _logger.LogDebug("Create new..."); - ret = new XmlStoreFilePersister(_runner, _store, _logger, true); - if (ret._runner == null) - { - // could not enlist with the runner, runner is completed, must run now - _logger.LogDebug("Runner is down, run now."); - runNow = true; - } - } - } - - else if (_timer == null) // we don't have a timer yet - { - _logger.LogDebug("Touched, was idle, start and save in {WaitMilliseconds}ms.", WaitMilliseconds); - _initialTouch = DateTime.Now; - _timer = new Timer(_ => TimerRelease()); - _timer.Change(WaitMilliseconds, 0); - } - - else // we have a timer - { - // change the timer to trigger in WaitMilliseconds unless we've been touched first more - // than MaxWaitMilliseconds ago and then leave the time unchanged - - if (DateTime.Now - _initialTouch < TimeSpan.FromMilliseconds(MaxWaitMilliseconds)) - { - _logger.LogDebug("Touched, was waiting, can delay, save in {WaitMilliseconds}ms.", WaitMilliseconds); - _timer.Change(WaitMilliseconds, 0); - } - else - { - _logger.LogDebug("Touched, was waiting, cannot delay."); - } - } - } - - // note: this comes from 7.x where it was not possible to lock the entire content service - // in our case, the XmlStore configures everything so that it is not possible to access content - // when going down, so this should never happen. - - if (runNow) - //Run(); - _logger.LogWarning("Cannot write now because we are going down, changes may be lost."); - - return ret; // this, by default, unless we created a new one - } - - private void TimerRelease() - { - lock (_locko) - { - _logger.LogDebug("Timer: release."); - _released = true; - - Release(); - } - } - - public override bool IsAsync => false; - - public override void Run() - { - lock (_locko) - { - _logger.LogDebug("Run now (sync)."); - // not really needed but safer (it's only us invoking Run, but the method is public...) - _released = true; - } - - using (_runLock.Lock()) - { - _store.SaveXmlToFile(); - } - } - - protected override void DisposeResources() - { - base.DisposeResources(); - - // stop the timer - if (_timer == null) return; - _timer.Change(Timeout.Infinite, Timeout.Infinite); - _timer.Dispose(); - } - } -} diff --git a/tests/Umbraco.Tests/Models/ContentXmlTest.cs b/tests/Umbraco.Tests/Models/ContentXmlTest.cs deleted file mode 100644 index 184bec85c235..000000000000 --- a/tests/Umbraco.Tests/Models/ContentXmlTest.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Linq; -using System.Xml.Linq; -using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Extensions; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; -using Umbraco.Tests.Testing; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Tests.Models -{ - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class ContentXmlTest : TestWithDatabaseBase - { - [Test] - public void Can_Generate_Xml_Representation_Of_Content() - { - // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! - ServiceContext.ContentTypeService.Save(contentType); - - var content = MockedContent.CreateTextpageContent(contentType, "Root Home", -1); - ServiceContext.ContentService.Save(content, Constants.Security.SuperUserId); - - var nodeName = content.ContentType.Alias.ToSafeAlias(ShortStringHelper); - var urlName = content.GetUrlSegment(ShortStringHelper, new[]{new DefaultUrlSegmentProvider(ShortStringHelper) }); - - // Act - XElement element = content.ToXml(Factory.GetRequiredService()); - - // Assert - Assert.That(element, Is.Not.Null); - Assert.That(element.Name.LocalName, Is.EqualTo(nodeName)); - Assert.AreEqual(content.Id.ToString(), (string)element.Attribute("id")); - Assert.AreEqual(content.ParentId.ToString(), (string)element.Attribute("parentID")); - Assert.AreEqual(content.Level.ToString(), (string)element.Attribute("level")); - Assert.AreEqual(content.CreatorId.ToString(), (string)element.Attribute("creatorID")); - Assert.AreEqual(content.SortOrder.ToString(), (string)element.Attribute("sortOrder")); - Assert.AreEqual(content.CreateDate.ToString("s"), (string)element.Attribute("createDate")); - Assert.AreEqual(content.UpdateDate.ToString("s"), (string)element.Attribute("updateDate")); - Assert.AreEqual(content.Name, (string)element.Attribute("nodeName")); - Assert.AreEqual(urlName, (string)element.Attribute("urlName")); - Assert.AreEqual(content.Path, (string)element.Attribute("path")); - Assert.AreEqual("", (string)element.Attribute("isDoc")); - Assert.AreEqual(content.ContentType.Id.ToString(), (string)element.Attribute("nodeType")); - Assert.AreEqual(content.GetCreatorProfile(ServiceContext.UserService).Name, (string)element.Attribute("creatorName")); - Assert.AreEqual(content.GetWriterProfile(ServiceContext.UserService).Name, (string)element.Attribute("writerName")); - Assert.AreEqual(content.WriterId.ToString(), (string)element.Attribute("writerID")); - Assert.AreEqual(content.TemplateId.ToString(), (string)element.Attribute("template")); - - Assert.AreEqual(content.Properties["title"].GetValue().ToString(), element.Elements("title").Single().Value); - Assert.AreEqual(content.Properties["bodyText"].GetValue().ToString(), element.Elements("bodyText").Single().Value); - Assert.AreEqual(content.Properties["keywords"].GetValue().ToString(), element.Elements("keywords").Single().Value); - Assert.AreEqual(content.Properties["description"].GetValue().ToString(), element.Elements("description").Single().Value); - } - } -} diff --git a/tests/Umbraco.Tests/Models/MediaXmlTest.cs b/tests/Umbraco.Tests/Models/MediaXmlTest.cs deleted file mode 100644 index 6899ddca6519..000000000000 --- a/tests/Umbraco.Tests/Models/MediaXmlTest.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System.Linq; -using System.Xml.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Extensions; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Tests.Models -{ - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class MediaXmlTest : TestWithDatabaseBase - { - [Test] - public void Can_Generate_Xml_Representation_Of_Media() - { - // Arrange - var mediaType = MockedContentTypes.CreateImageMediaType("image2"); - ServiceContext.MediaTypeService.Save(mediaType); - - // reference, so static ctor runs, so event handlers register - // and then, this will reset the width, height... because the file does not exist, of course ;-( - var loggerFactory = NullLoggerFactory.Instance; - var scheme = Mock.Of(); - var contentSettings = new ContentSettings(); - - var mediaFileManager = new MediaFileManager(Mock.Of(), scheme, - loggerFactory.CreateLogger(), ShortStringHelper); - var ignored = new FileUploadPropertyEditor(DataValueEditorFactory, mediaFileManager, Microsoft.Extensions.Options.Options.Create(contentSettings), DataTypeService, LocalizationService, LocalizedTextService, UploadAutoFillProperties, ContentService); - - var media = MockedMedia.CreateMediaImage(mediaType, -1); - media.WriterId = -1; // else it's zero and that's not a user and it breaks the tests - ServiceContext.MediaService.Save(media, Constants.Security.SuperUserId); - - // so we have to force-reset these values because the property editor has cleared them - media.SetValue(Constants.Conventions.Media.Width, "200"); - media.SetValue(Constants.Conventions.Media.Height, "200"); - media.SetValue(Constants.Conventions.Media.Bytes, "100"); - media.SetValue(Constants.Conventions.Media.Extension, "png"); - - var nodeName = media.ContentType.Alias.ToSafeAlias(ShortStringHelper); - var urlName = media.GetUrlSegment(ShortStringHelper, new[] { new DefaultUrlSegmentProvider(ShortStringHelper) }); - - // Act - XElement element = media.ToXml(Factory.GetRequiredService()); - - // Assert - Assert.That(element, Is.Not.Null); - Assert.That(element.Name.LocalName, Is.EqualTo(nodeName)); - Assert.AreEqual(media.Id.ToString(), (string)element.Attribute("id")); - Assert.AreEqual(media.ParentId.ToString(), (string)element.Attribute("parentID")); - Assert.AreEqual(media.Level.ToString(), (string)element.Attribute("level")); - Assert.AreEqual(media.SortOrder.ToString(), (string)element.Attribute("sortOrder")); - Assert.AreEqual(media.CreateDate.ToString("s"), (string)element.Attribute("createDate")); - Assert.AreEqual(media.UpdateDate.ToString("s"), (string)element.Attribute("updateDate")); - Assert.AreEqual(media.Name, (string)element.Attribute("nodeName")); - Assert.AreEqual(urlName, (string)element.Attribute("urlName")); - Assert.AreEqual(media.Path, (string)element.Attribute("path")); - Assert.AreEqual("", (string)element.Attribute("isDoc")); - Assert.AreEqual(media.ContentType.Id.ToString(), (string)element.Attribute("nodeType")); - Assert.AreEqual(media.GetCreatorProfile(ServiceContext.UserService).Name, (string)element.Attribute("writerName")); - Assert.AreEqual(media.CreatorId.ToString(), (string)element.Attribute("writerID")); - Assert.IsNull(element.Attribute("template")); - - Assert.AreEqual(media.Properties[Constants.Conventions.Media.File].GetValue().ToString(), element.Elements(Constants.Conventions.Media.File).Single().Value); - Assert.AreEqual(media.Properties[Constants.Conventions.Media.Width].GetValue().ToString(), element.Elements(Constants.Conventions.Media.Width).Single().Value); - Assert.AreEqual(media.Properties[Constants.Conventions.Media.Height].GetValue().ToString(), element.Elements(Constants.Conventions.Media.Height).Single().Value); - Assert.AreEqual(media.Properties[Constants.Conventions.Media.Bytes].GetValue().ToString(), element.Elements(Constants.Conventions.Media.Bytes).Single().Value); - Assert.AreEqual(media.Properties[Constants.Conventions.Media.Extension].GetValue().ToString(), element.Elements(Constants.Conventions.Media.Extension).Single().Value); - } - } -} diff --git a/tests/Umbraco.Tests/Persistence/FaultHandling/ConnectionRetryTest.cs b/tests/Umbraco.Tests/Persistence/FaultHandling/ConnectionRetryTest.cs deleted file mode 100644 index 4da04e5e17f6..000000000000 --- a/tests/Umbraco.Tests/Persistence/FaultHandling/ConnectionRetryTest.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Data.SqlClient; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Infrastructure.Persistence.Mappers; -using Umbraco.Tests.TestHelpers; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Tests.Persistence.FaultHandling -{ - [TestFixture, Ignore("fixme - ignored test")] - public class ConnectionRetryTest - { - [Test] - public void Cant_Connect_To_SqlDatabase_With_Invalid_User() - { - const string connectionString = @"server=.\SQLEXPRESS;database=EmptyForTest;user id=x;password=umbraco"; - const string providerName = Constants.DbProviderNames.SqlServer; - var factory = new UmbracoDatabaseFactory(Mock.Of>(), NullLoggerFactory.Instance, connectionString, providerName, new Lazy(() => Mock.Of()), TestHelper.DbProviderFactoryCreator, TestHelper.DatabaseSchemaCreatorFactory); - - using (var database = factory.CreateDatabase()) - { - Assert.Throws( - () => database.Fetch("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES")); - } - } - - [Test] - public void Cant_Connect_To_SqlDatabase_Because_Of_Network() - { - const string connectionString = @"server=.\SQLEXPRESS;database=EmptyForTest;user id=umbraco;password=umbraco"; - const string providerName = Constants.DbProviderNames.SqlServer; - var factory = new UmbracoDatabaseFactory(Mock.Of>(), NullLoggerFactory.Instance, connectionString, providerName, new Lazy(() => Mock.Of()), TestHelper.DbProviderFactoryCreator, TestHelper.DatabaseSchemaCreatorFactory); - - using (var database = factory.CreateDatabase()) - { - Assert.Throws( - () => database.Fetch("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES")); - } - } - } -} diff --git a/tests/Umbraco.Tests/Persistence/Mappers/MapperTestBase.cs b/tests/Umbraco.Tests/Persistence/Mappers/MapperTestBase.cs deleted file mode 100644 index 446d407077dc..000000000000 --- a/tests/Umbraco.Tests/Persistence/Mappers/MapperTestBase.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using Microsoft.Extensions.Options; -using Moq; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Infrastructure.Persistence.Mappers; -using Umbraco.Cms.Persistence.SqlCe; - -namespace Umbraco.Tests.Persistence.Mappers -{ - public class MapperTestBase - { - protected Lazy MockSqlContext() - { - var sqlContext = Mock.Of(); - var syntax = new SqlCeSyntaxProvider(Options.Create(new GlobalSettings())); - Mock.Get(sqlContext).Setup(x => x.SqlSyntax).Returns(syntax); - return new Lazy(() => sqlContext); - } - - protected MapperConfigurationStore CreateMaps() - => new MapperConfigurationStore(); - } -} diff --git a/tests/Umbraco.Tests/Persistence/NPocoTests/PetaPocoCachesTest.cs b/tests/Umbraco.Tests/Persistence/NPocoTests/PetaPocoCachesTest.cs deleted file mode 100644 index c27218e1b3a4..000000000000 --- a/tests/Umbraco.Tests/Persistence/NPocoTests/PetaPocoCachesTest.cs +++ /dev/null @@ -1,195 +0,0 @@ -using System; -using System.Linq; -using NUnit.Framework; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Services.Implement; -using Umbraco.Cms.Infrastructure.Serialization; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Extensions; -using Umbraco.Tests.Services; -using Umbraco.Tests.TestHelpers.Entities; - -namespace Umbraco.Tests.Persistence.NPocoTests -{ - // FIXME: npoco - what shall we do with those tests? - // - [TestFixture, Ignore("fixme - ignored test")] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class PetaPocoCachesTest : TestWithSomeContentBase - { - -#if DEBUG - /// - /// This tests the peta poco caches - /// - /// - /// This test WILL fail. This is because we cannot stop PetaPoco from creating more cached items for queries such as - /// ContentTypeRepository.GetAll(1,2,3,4); - /// when combined with other GetAll queries that pass in an array of Ids, each query generated for different length - /// arrays will produce a unique query which then gets added to the cache. - /// - /// This test confirms this, if you analyze the DIFFERENCE output below you can see why the cached queries grow. - /// - //[Test] - //public void Check_Peta_Poco_Caches() - //{ - // var result = new List>>(); - - // Database.PocoData.UseLongKeys = true; - - // for (int i = 0; i < 2; i++) - // { - // int id1, id2, id3; - // string alias; - // CreateStuff(out id1, out id2, out id3, out alias); - // QueryStuff(id1, id2, id3, alias); - - // double totalBytes1; - // IEnumerable keys; - // Console.Write(PocoData.PrintDebugCacheReport(out totalBytes1, out keys)); - - // result.Add(new Tuple>(totalBytes1, keys.Count(), keys)); - // } - - // for (int index = 0; index < result.Count; index++) - // { - // var tuple = result[index]; - // Console.WriteLine("Bytes: {0}, Delegates: {1}", tuple.Item1, tuple.Item2); - // if (index != 0) - // { - // Console.WriteLine("----------------DIFFERENCE---------------------"); - // var diff = tuple.Item3.Except(result[index - 1].Item3); - // foreach (var d in diff) - // { - // Console.WriteLine(d); - // } - // } - - // } - - // var allByteResults = result.Select(x => x.Item1).Distinct(); - // var totalKeys = result.Select(x => x.Item2).Distinct(); - - // Assert.AreEqual(1, allByteResults.Count()); - // Assert.AreEqual(1, totalKeys.Count()); - //} - - //[Test] - //public void Verify_Memory_Expires() - //{ - // Database.PocoData.SlidingExpirationSeconds = 2; - - // var managedCache = new Database.ManagedCache(); - - // int id1, id2, id3; - // string alias; - // CreateStuff(out id1, out id2, out id3, out alias); - // QueryStuff(id1, id2, id3, alias); - - // var count1 = managedCache.GetCache().GetCount(); - // Console.WriteLine("Keys = " + count1); - // Assert.Greater(count1, 0); - - // Thread.Sleep(10000); - - // var count2 = managedCache.GetCache().GetCount(); - // Console.WriteLine("Keys = " + count2); - // Assert.Less(count2, count1); - //} - - private void QueryStuff(int id1, int id2, int id3, string alias1) - { - var contentService = ServiceContext.ContentService; - - ServiceContext.TagService.GetTagsForEntity(id1); - - ServiceContext.TagService.GetAllContentTags(); - - ServiceContext.TagService.GetTagsForEntity(id2); - - ServiceContext.TagService.GetTagsForEntity(id3); - - contentService.CountDescendants(id3); - - contentService.CountChildren(id3); - - contentService.Count(documentTypeAlias: alias1); - - contentService.Count(); - - contentService.GetById(Guid.NewGuid()); - - contentService.GetByLevel(2); - - contentService.GetVersions(id3); - - contentService.GetRootContent(); - - contentService.GetContentForExpiration(DateTime.Now); - - contentService.GetContentForRelease(DateTime.Now); - - ((ContentService)contentService).GetPublishedDescendants(new Content("Test", -1, new ContentType(ShortStringHelper, -1)) - { - Id = id1, - Path = "-1," + id1 - }); - - contentService.GetVersion(1234); - } - - private void CreateStuff(out int id1, out int id2, out int id3, out string alias) - { - var contentService = ServiceContext.ContentService; - var serializer = new JsonNetSerializer(); - - var ctAlias = "umbTextpage" + Guid.NewGuid().ToString("N"); - alias = ctAlias; - - for (int i = 0; i < 20; i++) - { - contentService.CreateAndSave("Test", -1, "umbTextpage", 0); - } - var contentTypeService = ServiceContext.ContentTypeService; - var contentType = MockedContentTypes.CreateSimpleContentType(ctAlias, "test Doc Type"); - contentTypeService.Save(contentType); - for (int i = 0; i < 20; i++) - { - contentService.CreateAndSave("Test", -1, ctAlias, 0); - } - var parent = contentService.CreateAndSave("Test", -1, ctAlias, 0); - id1 = parent.Id; - - for (int i = 0; i < 20; i++) - { - contentService.CreateAndSave("Test", parent, ctAlias); - } - IContent current = parent; - for (int i = 0; i < 20; i++) - { - current = contentService.CreateAndSave("Test", current, ctAlias); - } - contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory" + Guid.NewGuid().ToString("N"), "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); - var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection.Value, DataTypeService, serializer, "tags", new[] { "hello", "world", "some", "tags" }); - content1.PublishCulture(CultureImpact.Invariant); - contentService.SaveAndPublish(content1); - id2 = content1.Id; - - var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); - content2.AssignTags(PropertyEditorCollection.Value, DataTypeService, serializer, "tags", new[] { "hello", "world", "some", "tags" }); - content2.PublishCulture(CultureImpact.Invariant); - contentService.SaveAndPublish(content2); - id3 = content2.Id; - - contentService.MoveToRecycleBin(content1); - } -#endif - } -} diff --git a/tests/Umbraco.Tests/Persistence/Querying/ContentTypeSqlMappingTests.cs b/tests/Umbraco.Tests/Persistence/Querying/ContentTypeSqlMappingTests.cs deleted file mode 100644 index fcf64641c8da..000000000000 --- a/tests/Umbraco.Tests/Persistence/Querying/ContentTypeSqlMappingTests.cs +++ /dev/null @@ -1,199 +0,0 @@ -// fixme - does it make any sense to keep these tests here? -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using NPoco; -//using NUnit.Framework; -//using Umbraco.Core; -//using Umbraco.Core.Models; -//using Umbraco.Core.Persistence.Dtos; -//using Umbraco.Core.Persistence.Repositories; -//using Umbraco.Core.Persistence.Repositories.Implement; -//using Umbraco.Tests.TestHelpers; -//using Umbraco.Tests.Testing; - -//namespace Umbraco.Tests.Persistence.Querying -//{ -// [TestFixture] -// [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] -// public class ContentTypeSqlMappingTests : TestWithDatabaseBase -// { -// [Test] -// public void Can_Map_Content_Type_Templates_And_Allowed_Types() -// { -// IDictionary.AssociatedTemplate>> allAssociatedTemplates; -// IDictionary> allParentContentTypeIds; -// IContentType[] contentTypes; - -// using (var scope = ScopeProvider.CreateScope()) -// { -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("umbracoNode")))); -// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 55554, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,55554", SortOrder = 1, UniqueId = new Guid("87D1EAB6-AB27-4852-B3DF-DE8DBA4A1AA0"), Text = "Template 1", NodeObjectType = Constants.ObjectTypes.Template, CreateDate = DateTime.Now }); -// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 55555, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,55555", SortOrder = 1, UniqueId = new Guid("3390BDF4-C974-4211-AA95-3812A8CE7C46"), Text = "Template 2", NodeObjectType = Constants.ObjectTypes.Template, CreateDate = DateTime.Now }); -// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99997, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99997", SortOrder = 0, UniqueId = new Guid("BB3241D5-6842-4EFA-A82A-5F56885CF528"), Text = "Test Content Type 1", NodeObjectType = Constants.ObjectTypes.DocumentType, CreateDate = DateTime.Now }); -// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99998, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99998", SortOrder = 0, UniqueId = new Guid("EEA66B06-302E-49BA-A8B2-EDF07248BC59"), Text = "Test Content Type 2", NodeObjectType = Constants.ObjectTypes.DocumentType, CreateDate = DateTime.Now }); -// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99999, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99999", SortOrder = 0, UniqueId = new Guid("C45CC083-BB27-4C1C-B448-6F703CC9B799"), Text = "Test Content Type 2", NodeObjectType = Constants.ObjectTypes.DocumentType, CreateDate = DateTime.Now }); -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("umbracoNode")))); - -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsTemplate")))); -// scope.Database.Insert("cmsTemplate", "pk", false, new TemplateDto { NodeId = 55554, Alias = "testTemplate1", PrimaryKey = 22221}); -// scope.Database.Insert("cmsTemplate", "pk", false, new TemplateDto { NodeId = 55555, Alias = "testTemplate2", PrimaryKey = 22222 }); -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsTemplate")))); - -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsContentType")))); -// scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88887, NodeId = 99997, Alias = "TestContentType1", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true }); -// scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88888, NodeId = 99998, Alias = "TestContentType2", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true }); -// scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88889, NodeId = 99999, Alias = "TestContentType3", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true }); -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsContentType")))); - -// scope.Database.Insert(new ContentTypeTemplateDto { ContentTypeNodeId = 99997, IsDefault = true, TemplateNodeId = 55555 }); -// scope.Database.Insert(new ContentTypeTemplateDto { ContentTypeNodeId = 99997, IsDefault = false, TemplateNodeId = 55554 }); - -// scope.Database.Insert(new ContentTypeAllowedContentTypeDto { AllowedId = 99998, Id = 99997, SortOrder = 1 }); -// scope.Database.Insert(new ContentTypeAllowedContentTypeDto { AllowedId = 99999, Id = 99997, SortOrder = 2}); - -// scope.Database.Insert(new ContentType2ContentTypeDto { ChildId = 99999, ParentId = 99997}); -// scope.Database.Insert(new ContentType2ContentTypeDto { ChildId = 99998, ParentId = 99997 }); - -// contentTypes = ContentTypeQueryMapper.GetContentTypes( -// scope.Database, out allAssociatedTemplates, out allParentContentTypeIds) -// .Where(x => new[] { 99997, 99998 }.Contains(x.Id)) -// .ToArray(); - -// scope.Complete(); -// } - -// var contentType1 = contentTypes.SingleOrDefault(x => x.Id == 99997); -// Assert.IsNotNull(contentType1); - -// var associatedTemplates1 = allAssociatedTemplates[contentType1.Id]; -// var parentContentTypes1 = allParentContentTypeIds[contentType1.Id]; - -// Assert.AreEqual(2, contentType1.AllowedContentTypes.Count()); -// Assert.AreEqual(2, associatedTemplates1.Count()); -// Assert.AreEqual(0, parentContentTypes1.Count()); - -// var contentType2 = contentTypes.SingleOrDefault(x => x.Id == 99998); -// Assert.IsNotNull(contentType2); - -// var associatedTemplates2 = allAssociatedTemplates[contentType2.Id]; -// var parentContentTypes2 = allParentContentTypeIds[contentType2.Id]; - -// Assert.AreEqual(0, contentType2.AllowedContentTypes.Count()); -// Assert.AreEqual(0, associatedTemplates2.Count()); -// Assert.AreEqual(1, parentContentTypes2.Count()); -// } - -// [Test] -// public void Can_Map_Media_Type_And_Allowed_Types() -// { -// IDictionary> allParentContentTypeIds; -// IMediaType[] contentTypes; - -// using (var scope = ScopeProvider.CreateScope()) -// { -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("umbracoNode")))); -// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99997, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99997", SortOrder = 0, UniqueId = new Guid("BB3241D5-6842-4EFA-A82A-5F56885CF528"), Text = "Test Media Type 1", NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now }); -// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99998, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99998", SortOrder = 0, UniqueId = new Guid("EEA66B06-302E-49BA-A8B2-EDF07248BC59"), Text = "Test Media Type 2", NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now }); -// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99999, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99999", SortOrder = 0, UniqueId = new Guid("C45CC083-BB27-4C1C-B448-6F703CC9B799"), Text = "Test Media Type 2", NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now }); -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("umbracoNode")))); - -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsContentType")))); -// scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88887, NodeId = 99997, Alias = "TestContentType1", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true }); -// scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88888, NodeId = 99998, Alias = "TestContentType2", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true }); -// scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88889, NodeId = 99999, Alias = "TestContentType3", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true }); -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsContentType")))); - -// scope.Database.Insert(new ContentTypeAllowedContentTypeDto { AllowedId = 99998, Id = 99997, SortOrder = 1 }); -// scope.Database.Insert(new ContentTypeAllowedContentTypeDto { AllowedId = 99999, Id = 99997, SortOrder = 2 }); - -// scope.Database.Insert(new ContentType2ContentTypeDto { ChildId = 99999, ParentId = 99997 }); -// scope.Database.Insert(new ContentType2ContentTypeDto { ChildId = 99998, ParentId = 99997 }); - -// contentTypes = ContentTypeQueryMapper.MapMediaTypes( -// scope.Database, SqlSyntax, out allParentContentTypeIds) -// .Where(x => (new[] { 99997, 99998 }).Contains(x.Id)) -// .ToArray(); - -// scope.Complete(); -// } - -// var contentType1 = contentTypes.SingleOrDefault(x => x.Id == 99997); -// Assert.IsNotNull(contentType1); - -// var parentContentTypes1 = allParentContentTypeIds[contentType1.Id]; - -// Assert.AreEqual(2, contentType1.AllowedContentTypes.Count()); -// Assert.AreEqual(0, parentContentTypes1.Count()); - -// var contentType2 = contentTypes.SingleOrDefault(x => x.Id == 99998); -// Assert.IsNotNull(contentType2); - -// var parentContentTypes2 = allParentContentTypeIds[contentType2.Id]; - -// Assert.AreEqual(0, contentType2.AllowedContentTypes.Count()); -// Assert.AreEqual(1, parentContentTypes2.Count()); - -// } - -// [Test] -// public void Can_Map_All_Property_Groups_And_Types() -// { -// IDictionary allPropTypeCollection; -// IDictionary allPropGroupCollection; - -// using (var scope = ScopeProvider.CreateScope()) -// { -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("umbracoNode")))); -// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 55555, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,55555", SortOrder = 1, UniqueId = new Guid("3390BDF4-C974-4211-AA95-3812A8CE7C46"), Text = "Test Data Type", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); -// scope.Database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 99999, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,99999", SortOrder = 0, UniqueId = new Guid("129241F0-D24E-4FC3-92D1-BC2D48B7C431"), Text = "Test Content Type", NodeObjectType = Constants.ObjectTypes.DocumentType, CreateDate = DateTime.Now }); -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("umbracoNode")))); - -// scope.Database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 55555, EditorAlias = Constants.PropertyEditors.Aliases.TextBox, DbType = "Nvarchar" }); - -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsContentType")))); -// scope.Database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 88888, NodeId = 99999, Alias = "TestContentType", Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true }); -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsContentType")))); - -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsPropertyTypeGroup")))); -// scope.Database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 77776, UniqueId = 77776.ToGuid(), ContentTypeNodeId = 99999, Text = "Group1", SortOrder = 1 }); -// scope.Database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 77777, UniqueId = 77777.ToGuid(), ContentTypeNodeId = 99999, Text = "Group2", SortOrder = 2 }); -// scope.Database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 77778, UniqueId = 77778.ToGuid(), ContentTypeNodeId = 99999, Text = "Group3", SortOrder = 3 }); -// scope.Database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 77779, UniqueId = 77779.ToGuid(), ContentTypeNodeId = 99999, Text = "Group4", SortOrder = 4 }); -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsPropertyTypeGroup")))); - -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntax.GetQuotedTableName("cmsPropertyType")))); -// scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66662, UniqueId = 66662.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77776, Alias = "property1", Name = "Property 1", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null }); -// scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66663, UniqueId = 66663.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77776, Alias = "property2", Name = "Property 2", SortOrder = 1, Mandatory = false, ValidationRegExp = null, Description = null }); -// scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66664, UniqueId = 66664.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77777, Alias = "property3", Name = "Property 3", SortOrder = 2, Mandatory = false, ValidationRegExp = null, Description = null }); -// scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66665, UniqueId = 66665.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77777, Alias = "property4", Name = "Property 4", SortOrder = 3, Mandatory = false, ValidationRegExp = null, Description = null }); -// scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66666, UniqueId = 66666.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = null, Alias = "property5", Name = "Property 5", SortOrder = 4, Mandatory = false, ValidationRegExp = null, Description = null }); -// scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66667, UniqueId = 66667.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77778, Alias = "property6", Name = "Property 6", SortOrder = 5, Mandatory = false, ValidationRegExp = null, Description = null }); -// scope.Database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 66668, UniqueId = 66668.ToGuid(), DataTypeId = 55555, ContentTypeId = 99999, PropertyTypeGroupId = 77778, Alias = "property7", Name = "Property 7", SortOrder = 6, Mandatory = false, ValidationRegExp = null, Description = null }); -// scope.Database.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF ", SqlSyntax.GetQuotedTableName("cmsPropertyType")))); - -// ContentTypeQueryMapper.MapGroupsAndProperties_(new[] { 99999 }, scope.Database, SqlSyntax, true, out allPropTypeCollection, out allPropGroupCollection); - -// scope.Complete(); -// } - -// var propGroupCollection = allPropGroupCollection[99999]; -// var propTypeCollection = allPropTypeCollection[99999]; - -// Assert.AreEqual(4, propGroupCollection.Count); -// Assert.AreEqual(2, propGroupCollection["Group1"].PropertyTypes.Count); -// Assert.IsTrue(propGroupCollection["Group1"].PropertyTypes.Contains("property1")); -// Assert.IsTrue(propGroupCollection["Group1"].PropertyTypes.Contains("property2")); -// Assert.AreEqual(2, propGroupCollection["Group2"].PropertyTypes.Count); -// Assert.IsTrue(propGroupCollection["Group2"].PropertyTypes.Contains("property3")); -// Assert.IsTrue(propGroupCollection["Group2"].PropertyTypes.Contains("property4")); -// Assert.AreEqual(2, propGroupCollection["Group3"].PropertyTypes.Count); -// Assert.IsTrue(propGroupCollection["Group3"].PropertyTypes.Contains("property6")); -// Assert.IsTrue(propGroupCollection["Group3"].PropertyTypes.Contains("property7")); -// Assert.AreEqual(0, propGroupCollection["Group4"].PropertyTypes.Count); - -// Assert.AreEqual(1, propTypeCollection.Count); -// Assert.IsTrue(propTypeCollection.Contains("property5")); -// } -// } -//} diff --git a/tests/Umbraco.Tests/Plugins/PluginManagerTests.cs b/tests/Umbraco.Tests/Plugins/PluginManagerTests.cs deleted file mode 100644 index 44879eae2fa6..000000000000 --- a/tests/Umbraco.Tests/Plugins/PluginManagerTests.cs +++ /dev/null @@ -1,392 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Reflection; -using Moq; -using NUnit.Framework; -using SqlCE4Umbraco; -using umbraco; -using umbraco.businesslogic; -using umbraco.cms.businesslogic; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Profiling; -using Umbraco.Core.PropertyEditors; -using umbraco.DataLayer; -using umbraco.editorControls; -using umbraco.interfaces; -using umbraco.MacroEngines; -using umbraco.uicontrols; -using Umbraco.Web; -using Umbraco.Web.PropertyEditors; - -namespace Umbraco.Tests.Plugins -{ - - [TestFixture] - public class PluginManagerTests - { - private PluginManager _manager; - [SetUp] - public void Initialize() - { - //this ensures its reset - _manager = new PluginManager(new ActivatorServiceProvider(), new NullCacheProvider(), - new ProfilingLogger(Mock.Of(), Mock.Of())); - - //for testing, we'll specify which assemblies are scanned for the PluginTypeResolver - //TODO: Should probably update this so it only searches this assembly and add custom types to be found - _manager.AssembliesToScan = new[] - { - this.GetType().Assembly, - typeof(ApplicationStartupHandler).Assembly, - typeof(SqlCEHelper).Assembly, - typeof(CMSNode).Assembly, - typeof(System.Guid).Assembly, - typeof(NUnit.Framework.Assert).Assembly, - typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly, - typeof(System.Xml.NameTable).Assembly, - typeof(System.Configuration.GenericEnumConverter).Assembly, - typeof(System.Web.SiteMap).Assembly, - typeof(TabPage).Assembly, - typeof(System.Web.Mvc.ActionResult).Assembly, - typeof(TypeFinder).Assembly, - typeof(ISqlHelper).Assembly, - typeof(ICultureDictionary).Assembly, - typeof(UmbracoContext).Assembly, - typeof(BaseDataType).Assembly - }; - } - - [TearDown] - public void TearDown() - { - _manager = null; - } - - private DirectoryInfo PrepareFolder() - { - var assDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; - var dir = Directory.CreateDirectory(Path.Combine(assDir.FullName, "PluginManager", Guid.NewGuid().ToString("N"))); - foreach (var f in dir.GetFiles()) - { - f.Delete(); - } - return dir; - } - - //[Test] - //public void Scan_Vs_Load_Benchmark() - //{ - // var pluginManager = new PluginManager(false); - // var watch = new Stopwatch(); - // watch.Start(); - // for (var i = 0; i < 1000; i++) - // { - // var type2 = Type.GetType("umbraco.macroCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // var type3 = Type.GetType("umbraco.templateCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // var type4 = Type.GetType("umbraco.presentation.cache.MediaLibraryRefreshers, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // var type5 = Type.GetType("umbraco.presentation.cache.pageRefresher, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // } - // watch.Stop(); - // Debug.WriteLine("TOTAL TIME (1st round): " + watch.ElapsedMilliseconds); - // watch.Start(); - // for (var i = 0; i < 1000; i++) - // { - // var type2 = BuildManager.GetType("umbraco.macroCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // var type3 = BuildManager.GetType("umbraco.templateCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // var type4 = BuildManager.GetType("umbraco.presentation.cache.MediaLibraryRefreshers, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // var type5 = BuildManager.GetType("umbraco.presentation.cache.pageRefresher, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // } - // watch.Stop(); - // Debug.WriteLine("TOTAL TIME (1st round): " + watch.ElapsedMilliseconds); - // watch.Reset(); - // watch.Start(); - // for (var i = 0; i < 1000; i++) - // { - // var refreshers = pluginManager.ResolveTypes(false); - // } - // watch.Stop(); - // Debug.WriteLine("TOTAL TIME (2nd round): " + watch.ElapsedMilliseconds); - //} - - ////NOTE: This test shows that Type.GetType is 100% faster than Assembly.Load(..).GetType(...) so we'll use that :) - //[Test] - //public void Load_Type_Benchmark() - //{ - // var watch = new Stopwatch(); - // watch.Start(); - // for (var i = 0; i < 1000; i++) - // { - // var type2 = Type.GetType("umbraco.macroCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // var type3 = Type.GetType("umbraco.templateCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // var type4 = Type.GetType("umbraco.presentation.cache.MediaLibraryRefreshers, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // var type5 = Type.GetType("umbraco.presentation.cache.pageRefresher, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null"); - // } - // watch.Stop(); - // Debug.WriteLine("TOTAL TIME (1st round): " + watch.ElapsedMilliseconds); - // watch.Reset(); - // watch.Start(); - // for (var i = 0; i < 1000; i++) - // { - // var type2 = Assembly.Load("umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null") - // .GetType("umbraco.macroCacheRefresh"); - // var type3 = Assembly.Load("umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null") - // .GetType("umbraco.templateCacheRefresh"); - // var type4 = Assembly.Load("umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null") - // .GetType("umbraco.presentation.cache.MediaLibraryRefreshers"); - // var type5 = Assembly.Load("umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null") - // .GetType("umbraco.presentation.cache.pageRefresher"); - // } - // watch.Stop(); - // Debug.WriteLine("TOTAL TIME (2nd round): " + watch.ElapsedMilliseconds); - // watch.Reset(); - // watch.Start(); - // for (var i = 0; i < 1000; i++) - // { - // var type2 = BuildManager.GetType("umbraco.macroCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // var type3 = BuildManager.GetType("umbraco.templateCacheRefresh, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // var type4 = BuildManager.GetType("umbraco.presentation.cache.MediaLibraryRefreshers, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // var type5 = BuildManager.GetType("umbraco.presentation.cache.pageRefresher, umbraco, Version=1.0.4698.259, Culture=neutral, PublicKeyToken=null", true); - // } - // watch.Stop(); - // Debug.WriteLine("TOTAL TIME (1st round): " + watch.ElapsedMilliseconds); - //} - - [Test] - public void Detect_Legacy_Plugin_File_List() - { - var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/PluginCache"); - - var filePath= Path.Combine(tempFolder, string.Format("umbraco-plugins.{0}.list", NetworkHelper.FileSafeMachineName)); - - File.WriteAllText(filePath, @" - - - - -"); - - Assert.IsEmpty(_manager.ReadCache()); // uber-legacy cannot be read - - File.Delete(filePath); - - File.WriteAllText(filePath, @" - - - - -"); - - Assert.IsEmpty(_manager.ReadCache()); // legacy cannot be read - - File.Delete(filePath); - - File.WriteAllText(filePath, @"IContentFinder - -MyContentFinder -AnotherContentFinder - -"); - - Assert.IsNotNull(_manager.ReadCache()); // works - } - - [Test] - public void Create_Cached_Plugin_File() - { - var types = new[] { typeof (PluginManager), typeof (PluginManagerTests), typeof (UmbracoContext) }; - - var typeList1 = new PluginManager.TypeList(typeof (object), null); - foreach (var type in types) typeList1.Add(type); - _manager.AddTypeList(typeList1); - _manager.WriteCache(); - - var plugins = _manager.TryGetCached(typeof (object), null); - var diffType = _manager.TryGetCached(typeof (object), typeof (ObsoleteAttribute)); - - Assert.IsTrue(plugins.Success); - //this will be false since there is no cache of that type resolution kind - Assert.IsFalse(diffType.Success); - - Assert.AreEqual(3, plugins.Result.Count()); - var shouldContain = types.Select(x => x.AssemblyQualifiedName); - //ensure they are all found - Assert.IsTrue(plugins.Result.ContainsAll(shouldContain)); - } - - [Test] - public void Get_Plugins_Hash() - { - //Arrange - var dir = PrepareFolder(); - var d1 = dir.CreateSubdirectory("1"); - var d2 = dir.CreateSubdirectory("2"); - var d3 = dir.CreateSubdirectory("3"); - var d4 = dir.CreateSubdirectory("4"); - var f1 = new FileInfo(Path.Combine(d1.FullName, "test1.dll")); - var f2 = new FileInfo(Path.Combine(d1.FullName, "test2.dll")); - var f3 = new FileInfo(Path.Combine(d2.FullName, "test1.dll")); - var f4 = new FileInfo(Path.Combine(d2.FullName, "test2.dll")); - var f5 = new FileInfo(Path.Combine(d3.FullName, "test1.dll")); - var f6 = new FileInfo(Path.Combine(d3.FullName, "test2.dll")); - var f7 = new FileInfo(Path.Combine(d4.FullName, "test1.dll")); - f1.CreateText().Close(); - f2.CreateText().Close(); - f3.CreateText().Close(); - f4.CreateText().Close(); - f5.CreateText().Close(); - f6.CreateText().Close(); - f7.CreateText().Close(); - var list1 = new[] { f1, f2, f3, f4, f5, f6 }; - var list2 = new[] { f1, f3, f5 }; - var list3 = new[] { f1, f3, f5, f7 }; - - //Act - var hash1 = PluginManager.GetFileHash(list1, new ProfilingLogger(Mock.Of(), Mock.Of())); - var hash2 = PluginManager.GetFileHash(list2, new ProfilingLogger(Mock.Of(), Mock.Of())); - var hash3 = PluginManager.GetFileHash(list3, new ProfilingLogger(Mock.Of(), Mock.Of())); - - //Assert - Assert.AreNotEqual(hash1, hash2); - Assert.AreNotEqual(hash1, hash3); - Assert.AreNotEqual(hash2, hash3); - - Assert.AreEqual(hash1, PluginManager.GetFileHash(list1, new ProfilingLogger(Mock.Of(), Mock.Of()))); - } - - [Test] - public void Ensure_Only_One_Type_List_Created() - { - var foundTypes1 = _manager.ResolveFindMeTypes(); - var foundTypes2 = _manager.ResolveFindMeTypes(); - Assert.AreEqual(1, _manager.TypeLists.Count(x => x.BaseType == typeof(IFindMe) && x.AttributeType == null)); - } - - [Test] - public void Resolves_Assigned_Mappers() - { - var foundTypes1 = _manager.ResolveAssignedMapperTypes(); - Assert.AreEqual(31, foundTypes1.Count()); - } - - [Test] - public void Resolves_Types() - { - var foundTypes1 = _manager.ResolveFindMeTypes(); - Assert.AreEqual(2, foundTypes1.Count()); - } - - [Test] - public void Resolves_Attributed_Trees() - { - var trees = _manager.ResolveAttributedTrees(); - Assert.AreEqual(5, trees.Count()); - } - - [Test] - public void Resolves_Actions() - { - var actions = _manager.ResolveActions(); - Assert.AreEqual(38, actions.Count()); - } - - [Test] - public void Resolves_Trees() - { - var trees = _manager.ResolveTrees(); - Assert.AreEqual(33, trees.Count()); - } - - [Test] - public void Resolves_Applications() - { - var apps = _manager.ResolveApplications(); - Assert.AreEqual(7, apps.Count()); - } - - [Test] - public void Resolves_DataTypes() - { - var types = _manager.ResolveDataTypes(); - Assert.AreEqual(35, types.Count()); - } - - [Test] - public void Resolves_RazorDataTypeModels() - { - var types = _manager.ResolveRazorDataTypeModels(); - Assert.AreEqual(2, types.Count()); - } - - [Test] - public void Resolves_RestExtensions() - { - var types = _manager.ResolveRestExtensions(); - Assert.AreEqual(2, types.Count()); - } - - [Test] - public void Resolves_XsltExtensions() - { - var types = _manager.ResolveXsltExtensions(); - Assert.AreEqual(3, types.Count()); - } - - /// - /// This demonstrates this issue: http://issues.umbraco.org/issue/U4-3505 - the TypeList was returning a list of assignable types - /// not explicit types which is sort of ideal but is confusing so we'll do it the less confusing way. - /// - [Test] - public void TypeList_Resolves_Explicit_Types() - { - var types = new HashSet(); - - var propEditors = new PluginManager.TypeList(typeof (PropertyEditor), null); - propEditors.Add(typeof(LabelPropertyEditor)); - types.Add(propEditors); - - var found = types.SingleOrDefault(x => x.BaseType == typeof (PropertyEditor) && x.AttributeType == null); - - Assert.IsNotNull(found); - - //This should not find a type list of this type - var shouldNotFind = types.SingleOrDefault(x => x.BaseType == typeof (IParameterEditor) && x.AttributeType == null); - - Assert.IsNull(shouldNotFind); - } - - [XsltExtension("Blah.Blah")] - public class MyXsltExtension - { - - } - - - [Umbraco.Web.BaseRest.RestExtension("Blah")] - public class MyRestExtesion - { - - } - - public interface IFindMe : IDiscoverable - { - - } - - public class FindMe1 : IFindMe - { - - } - - public class FindMe2 : IFindMe - { - - } - - } -} diff --git a/tests/Umbraco.Tests/PublishedContent/NuCacheTests.cs b/tests/Umbraco.Tests/PublishedContent/NuCacheTests.cs deleted file mode 100644 index 3f1bd0963975..000000000000 --- a/tests/Umbraco.Tests/PublishedContent/NuCacheTests.cs +++ /dev/null @@ -1,316 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Services.Changes; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Infrastructure.PublishedCache; -using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; -using Umbraco.Cms.Infrastructure.Serialization; -using Umbraco.Cms.Tests.Common; -using Umbraco.Extensions; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing.Objects; -using Umbraco.Web.Composing; - -namespace Umbraco.Tests.PublishedContent -{ - [TestFixture] - public class NuCacheTests - { - private IPublishedSnapshotService _snapshotService; - private IVariationContextAccessor _variationAccesor; - private IContentCacheDataSerializerFactory _contentNestedDataSerializerFactory; - private ContentType _contentType; - private PropertyType _propertyType; - - [TearDown] - public void Teardown() - { - _snapshotService?.Dispose(); - } - - private void Init() - { - var factory = Mock.Of(); - Current.Factory = factory; - - var publishedModelFactory = new NoopPublishedModelFactory(); - Mock.Get(factory).Setup(x => x.GetService(typeof(IPublishedModelFactory))).Returns(publishedModelFactory); - Mock.Get(factory).Setup(x => x.GetService(typeof(IPublishedValueFallback))).Returns(new NoopPublishedValueFallback()); - - // create a content node kit - var kit = new ContentNodeKit - { - ContentTypeId = 2, - Node = new ContentNode(1, Guid.NewGuid(), 0, "-1,1", 0, -1, DateTime.Now, 0), - DraftData = new ContentData - { - Name = "It Works2!", - Published = false, - TemplateId = 0, - VersionId = 2, - VersionDate = DateTime.Now, - WriterId = 0, - Properties = new Dictionary { { "prop", new[] - { - new PropertyData { Culture = "", Segment = "", Value = "val2" }, - new PropertyData { Culture = "fr-FR", Segment = "", Value = "val-fr2" }, - new PropertyData { Culture = "en-UK", Segment = "", Value = "val-uk2" }, - new PropertyData { Culture = "dk-DA", Segment = "", Value = "val-da2" }, - new PropertyData { Culture = "de-DE", Segment = "", Value = "val-de2" } - } } }, - CultureInfos = new Dictionary - { - // draft data = everything, and IsDraft indicates what's edited - { "fr-FR", new CultureVariation { Name = "name-fr2", IsDraft = true, Date = new DateTime(2018, 01, 03, 01, 00, 00) } }, - { "en-UK", new CultureVariation { Name = "name-uk2", IsDraft = true, Date = new DateTime(2018, 01, 04, 01, 00, 00) } }, - { "dk-DA", new CultureVariation { Name = "name-da2", IsDraft = true, Date = new DateTime(2018, 01, 05, 01, 00, 00) } }, - { "de-DE", new CultureVariation { Name = "name-de1", IsDraft = false, Date = new DateTime(2018, 01, 02, 01, 00, 00) } } - } - }, - PublishedData = new ContentData - { - Name = "It Works1!", - Published = true, - TemplateId = 0, - VersionId = 1, - VersionDate = DateTime.Now, - WriterId = 0, - Properties = new Dictionary { { "prop", new[] - { - new PropertyData { Culture = "", Segment = "", Value = "val1" }, - new PropertyData { Culture = "fr-FR", Segment = "", Value = "val-fr1" }, - new PropertyData { Culture = "en-UK", Segment = "", Value = "val-uk1" } - } } }, - CultureInfos = new Dictionary - { - // published data = only what's actually published, and IsDraft has to be false - { "fr-FR", new CultureVariation { Name = "name-fr1", IsDraft = false, Date = new DateTime(2018, 01, 01, 01, 00, 00) } }, - { "en-UK", new CultureVariation { Name = "name-uk1", IsDraft = false, Date = new DateTime(2018, 01, 02, 01, 00, 00) } }, - { "de-DE", new CultureVariation { Name = "name-de1", IsDraft = false, Date = new DateTime(2018, 01, 02, 01, 00, 00) } } - } - } - }; - - // create a data source for NuCache - var dataSource = new TestDataSource(kit); - _contentNestedDataSerializerFactory = new JsonContentNestedDataSerializerFactory(); - - var runtime = Mock.Of(); - Mock.Get(runtime).Setup(x => x.Level).Returns(RuntimeLevel.Run); - - var serializer = new ConfigurationEditorJsonSerializer(); - - // create data types, property types and content types - var dataType = new DataType(new VoidEditor("Editor", Mock.Of()), serializer) { Id = 3 }; - - var dataTypes = new[] - { - dataType - }; - - _propertyType = new PropertyType(TestHelper.ShortStringHelper, "Umbraco.Void.Editor", ValueStorageType.Nvarchar) { Alias = "prop", DataTypeId = 3, Variations = ContentVariation.Culture }; - _contentType = new ContentType(TestHelper.ShortStringHelper, -1) { Id = 2, Alias = "alias-ct", Variations = ContentVariation.Culture }; - _contentType.AddPropertyType(_propertyType); - - var contentTypes = new[] - { - _contentType - }; - - var contentTypeService = new Mock(); - contentTypeService.Setup(x => x.GetAll()).Returns(contentTypes); - contentTypeService.Setup(x => x.GetAll(It.IsAny())).Returns(contentTypes); - - var mediaTypeService = new Mock(); - mediaTypeService.Setup(x => x.GetAll()).Returns(Enumerable.Empty()); - mediaTypeService.Setup(x => x.GetAll(It.IsAny())).Returns(Enumerable.Empty()); - - var contentTypeServiceBaseFactory = new Mock(); - contentTypeServiceBaseFactory.Setup(x => x.For(It.IsAny())).Returns(contentTypeService.Object); - - var dataTypeService = Mock.Of(); - Mock.Get(dataTypeService).Setup(x => x.GetAll()).Returns(dataTypes); - - // create a service context - var serviceContext = ServiceContext.CreatePartial( - dataTypeService: dataTypeService, - memberTypeService: Mock.Of(), - memberService: Mock.Of(), - contentTypeService: contentTypeService.Object, - mediaTypeService: mediaTypeService.Object, - localizationService: Mock.Of(), - domainService: Mock.Of() - ); - - // create a scope provider - var scopeProvider = Mock.Of(); - Mock.Get(scopeProvider) - .Setup(x => x.CreateScope( - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny())) - .Returns(Mock.Of); - - // create a published content type factory - var contentTypeFactory = new PublishedContentTypeFactory( - publishedModelFactory, - new PropertyValueConverterCollection(Array.Empty()), - dataTypeService); - - // create a variation accessor - _variationAccesor = new TestVariationContextAccessor(); - - var typeFinder = TestHelper.GetTypeFinder(); - - var globalSettings = new GlobalSettings(); - var nuCacheSettings = new NuCacheSettings(); - - // at last, create the complete NuCache snapshot service! - var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; - _snapshotService = new PublishedSnapshotService( - options, - null, - serviceContext, - contentTypeFactory, - new TestPublishedSnapshotAccessor(), - _variationAccesor, - Mock.Of(), - NullLoggerFactory.Instance, - scopeProvider, - dataSource, - new TestDefaultCultureAccessor(), - Microsoft.Extensions.Options.Options.Create(globalSettings), - Mock.Of(), - publishedModelFactory, - TestHelper.GetHostingEnvironment(), - Microsoft.Extensions.Options.Options.Create(nuCacheSettings), - _contentNestedDataSerializerFactory); - - // invariant is the current default - _variationAccesor.VariationContext = new VariationContext(); - - Mock.Get(factory).Setup(x => x.GetService(typeof(IVariationContextAccessor))).Returns(_variationAccesor); - } - - [Test] - public void StandaloneVariations() - { - // this test implements a full standalone NuCache (based upon a test IDataSource, does not - // use any local db files, does not rely on any database) - and tests variations - - Init(); - - // get a snapshot, get a published content - var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - var publishedContent = snapshot.Content.GetById(1); - - Assert.IsNotNull(publishedContent); - Assert.AreEqual("val1", publishedContent.Value(Mock.Of(), "prop")); - Assert.AreEqual("val-fr1", publishedContent.Value(Mock.Of(), "prop", "fr-FR")); - Assert.AreEqual("val-uk1", publishedContent.Value(Mock.Of(), "prop", "en-UK")); - - Assert.IsNull(publishedContent.Name(_variationAccesor)); // no invariant name for varying content - Assert.AreEqual("name-fr1", publishedContent.Name(_variationAccesor, "fr-FR")); - Assert.AreEqual("name-uk1", publishedContent.Name(_variationAccesor, "en-UK")); - - var draftContent = snapshot.Content.GetById(true, 1); - Assert.AreEqual("val2", draftContent.Value(Mock.Of(), "prop")); - Assert.AreEqual("val-fr2", draftContent.Value(Mock.Of(), "prop", "fr-FR")); - Assert.AreEqual("val-uk2", draftContent.Value(Mock.Of(), "prop", "en-UK")); - - Assert.IsNull(draftContent.Name(_variationAccesor)); // no invariant name for varying content - Assert.AreEqual("name-fr2", draftContent.Name(_variationAccesor, "fr-FR")); - Assert.AreEqual("name-uk2", draftContent.Name(_variationAccesor, "en-UK")); - - // now french is default - _variationAccesor.VariationContext = new VariationContext("fr-FR"); - Assert.AreEqual("val-fr1", publishedContent.Value(Mock.Of(), "prop")); - Assert.AreEqual("name-fr1", publishedContent.Name(_variationAccesor)); - Assert.AreEqual(new DateTime(2018, 01, 01, 01, 00, 00), publishedContent.CultureDate(_variationAccesor)); - - // now uk is default - _variationAccesor.VariationContext = new VariationContext("en-UK"); - Assert.AreEqual("val-uk1", publishedContent.Value(Mock.Of(), "prop")); - Assert.AreEqual("name-uk1", publishedContent.Name(_variationAccesor)); - Assert.AreEqual(new DateTime(2018, 01, 02, 01, 00, 00), publishedContent.CultureDate(_variationAccesor)); - - // invariant needs to be retrieved explicitly, when it's not default - Assert.AreEqual("val1", publishedContent.Value(Mock.Of(), "prop", culture: "")); - - // but, - // if the content type / property type does not vary, then it's all invariant again - // modify the content type and property type, notify the snapshot service - _contentType.Variations = ContentVariation.Nothing; - _propertyType.Variations = ContentVariation.Nothing; - _snapshotService.Notify(new[] { new ContentTypeCacheRefresher.JsonPayload("IContentType", publishedContent.ContentType.Id, ContentTypeChangeTypes.RefreshMain) }); - - // get a new snapshot (nothing changed in the old one), get the published content again - var anotherSnapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null); - var againContent = anotherSnapshot.Content.GetById(1); - - Assert.AreEqual(ContentVariation.Nothing, againContent.ContentType.Variations); - Assert.AreEqual(ContentVariation.Nothing, againContent.ContentType.GetPropertyType("prop").Variations); - - // now, "no culture" means "invariant" - Assert.AreEqual("It Works1!", againContent.Name(_variationAccesor)); - Assert.AreEqual("val1", againContent.Value(Mock.Of(), "prop")); - } - - [Test] - public void IsDraftIsPublished() - { - Init(); - - // get the published published content - var s = _snapshotService.CreatePublishedSnapshot(null); - var c1 = s.Content.GetById(1); - - // published content = nothing is draft here - Assert.IsFalse(c1.IsDraft("fr-FR")); - Assert.IsFalse(c1.IsDraft("en-UK")); - Assert.IsFalse(c1.IsDraft("dk-DA")); - Assert.IsFalse(c1.IsDraft("de-DE")); - - // and only those with published name, are published - Assert.IsTrue(c1.IsPublished("fr-FR")); - Assert.IsTrue(c1.IsPublished("en-UK")); - Assert.IsFalse(c1.IsDraft("dk-DA")); - Assert.IsTrue(c1.IsPublished("de-DE")); - - // get the draft published content - var c2 = s.Content.GetById(true, 1); - - // draft content = we have drafts - Assert.IsTrue(c2.IsDraft("fr-FR")); - Assert.IsTrue(c2.IsDraft("en-UK")); - Assert.IsTrue(c2.IsDraft("dk-DA")); - Assert.IsFalse(c2.IsDraft("de-DE")); // except for the one that does not - - // and only those with published name, are published - Assert.IsTrue(c2.IsPublished("fr-FR")); - Assert.IsTrue(c2.IsPublished("en-UK")); - Assert.IsFalse(c2.IsPublished("dk-DA")); - Assert.IsTrue(c2.IsPublished("de-DE")); - } - - } -} diff --git a/tests/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs b/tests/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs deleted file mode 100644 index 9140aec22aa9..000000000000 --- a/tests/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs +++ /dev/null @@ -1,182 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Infrastructure.Serialization; -using Umbraco.Extensions; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests.PublishedContent -{ - /// - /// Unit tests for IPublishedContent and extensions - /// - [TestFixture] - public class PublishedContentDataTableTests : BaseWebTest - { - public override void SetUp() - { - base.SetUp(); - - // need to specify a different callback for testing - PublishedContentExtensions.GetPropertyAliasesAndNames = (contentTypeService, mediaTypeService, memberTypeService, alias) => - { - var userFields = new Dictionary() - { - {"property1", "Property 1"}, - {"property2", "Property 2"} - }; - if (alias == "Child") - { - userFields.Add("property4", "Property 4"); - } - else - { - userFields.Add("property3", "Property 3"); - } - - //ensure the standard fields are there - var allFields = new Dictionary() - { - {"Id", "Id"}, - {"NodeName", "NodeName"}, - {"NodeTypeAlias", "NodeTypeAlias"}, - {"CreateDate", "CreateDate"}, - {"UpdateDate", "UpdateDate"}, - {"CreatorId", "CreatorId"}, - {"WriterId", "WriterId"}, - {"Url", "Url"} - }; - foreach (var f in userFields.Where(f => !allFields.ContainsKey(f.Key))) - { - allFields.Add(f.Key, f.Value); - } - return allFields; - }; - var umbracoContext = GetUmbracoContext("/test"); - - //set the UmbracoContext.Current since the extension methods rely on it - Umbraco.Web.Composing.Current.UmbracoContextAccessor.UmbracoContext = umbracoContext; - } - - public override void TearDown() - { - base.TearDown(); - PublishedContentExtensions.GetPropertyAliasesAndNames = null; - } - - [Test] - public void To_DataTable() - { - var doc = GetContent(true, 1); - var dt = doc.ChildrenAsTable(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()); - - Assert.AreEqual(11, dt.Columns.Count); - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual("value4", dt.Rows[0]["Property 1"]); - Assert.AreEqual("value5", dt.Rows[0]["Property 2"]); - Assert.AreEqual("value6", dt.Rows[0]["Property 4"]); - Assert.AreEqual("value7", dt.Rows[1]["Property 1"]); - Assert.AreEqual("value8", dt.Rows[1]["Property 2"]); - Assert.AreEqual("value9", dt.Rows[1]["Property 4"]); - Assert.AreEqual("value10", dt.Rows[2]["Property 1"]); - Assert.AreEqual("value11", dt.Rows[2]["Property 2"]); - Assert.AreEqual("value12", dt.Rows[2]["Property 4"]); - } - - [Test] - public void To_DataTable_With_Filter() - { - var doc = GetContent(true, 1); - //change a doc type alias - var c = (SolidPublishedContent)doc.Children.ElementAt(0); - c.ContentType = new PublishedContentType(Guid.NewGuid(), 22, "DontMatch", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing); - - var dt = doc.ChildrenAsTable(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), "Child"); - - Assert.AreEqual(11, dt.Columns.Count); - Assert.AreEqual(2, dt.Rows.Count); - Assert.AreEqual("value7", dt.Rows[0]["Property 1"]); - Assert.AreEqual("value8", dt.Rows[0]["Property 2"]); - Assert.AreEqual("value9", dt.Rows[0]["Property 4"]); - Assert.AreEqual("value10", dt.Rows[1]["Property 1"]); - Assert.AreEqual("value11", dt.Rows[1]["Property 2"]); - Assert.AreEqual("value12", dt.Rows[1]["Property 4"]); - } - - [Test] - public void To_DataTable_No_Rows() - { - var doc = GetContent(false, 1); - var dt = doc.ChildrenAsTable(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()); - //will return an empty data table - Assert.AreEqual(0, dt.Columns.Count); - Assert.AreEqual(0, dt.Rows.Count); - } - - private IPublishedContent GetContent(bool createChildren, int indexVals) - { - var serializer = new ConfigurationEditorJsonSerializer(); - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(DataValueEditorFactory), serializer) { Id = 1 }); - - var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); - var contentTypeAlias = createChildren ? "Parent" : "Child"; - var contentType = new PublishedContentType(Guid.NewGuid(), 22, contentTypeAlias, PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing); - var d = new SolidPublishedContent(contentType) - { - CreateDate = DateTime.Now, - CreatorId = 1, - Id = 3, - SortOrder = 4, - TemplateId = 5, - UpdateDate = DateTime.Now, - Path = "-1,3", - UrlSegment = "home-page", - Name = "Page" + Guid.NewGuid(), - Version = Guid.NewGuid(), - WriterId = 1, - Parent = null, - Level = 1, - Children = new List() - }; - d.Properties = new Collection(new List - { - new RawValueProperty(factory.CreatePropertyType("property1", 1), d, "value" + indexVals), - new RawValueProperty(factory.CreatePropertyType("property2", 1), d, "value" + (indexVals + 1)) - }); - if (createChildren) - { - d.Children = new List() - { - GetContent(false, indexVals + 3), - GetContent(false, indexVals + 6), - GetContent(false, indexVals + 9) - }; - } - - if (!createChildren) - { - //create additional columns, used to test the different columns for child nodes - ((Collection) d.Properties).Add( - new RawValueProperty(factory.CreatePropertyType("property4",1), d, "value" + (indexVals + 2))); - } - else - { - ((Collection) d.Properties).Add( - new RawValueProperty(factory.CreatePropertyType("property3", 1), d, "value" + (indexVals + 2))); - } - - return d; - } - } -} diff --git a/tests/Umbraco.Tests/PublishedContent/PublishedContentExtensionTests.cs b/tests/Umbraco.Tests/PublishedContent/PublishedContentExtensionTests.cs deleted file mode 100644 index 67d861a564fb..000000000000 --- a/tests/Umbraco.Tests/PublishedContent/PublishedContentExtensionTests.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System.Collections.Generic; -using NUnit.Framework; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Extensions; -using Umbraco.Tests.Testing; - -namespace Umbraco.Tests.PublishedContent -{ - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class PublishedContentExtensionTests : PublishedContentTestBase - { - private IUmbracoContext _ctx; - private string _xmlContent = ""; - private bool _createContentTypes = true; - private Dictionary _contentTypes; - - protected override string GetXmlContent(int templateId) - { - return _xmlContent; - } - - [Test] - public void IsDocumentType_NonRecursive_ActualType_ReturnsTrue() - { - InitializeInheritedContentTypes(); - - var publishedContent = _ctx.Content.GetById(1100); - Assert.That(publishedContent.IsDocumentType("inherited", false)); - } - - [Test] - public void IsDocumentType_NonRecursive_BaseType_ReturnsFalse() - { - InitializeInheritedContentTypes(); - - var publishedContent = _ctx.Content.GetById(1100); - Assert.That(publishedContent.IsDocumentType("base", false), Is.False); - } - - [Test] - public void IsDocumentType_Recursive_ActualType_ReturnsTrue() - { - InitializeInheritedContentTypes(); - - var publishedContent = _ctx.Content.GetById(1100); - Assert.That(publishedContent.IsDocumentType("inherited", true)); - } - - [Test] - public void IsDocumentType_Recursive_BaseType_ReturnsTrue() - { - InitializeInheritedContentTypes(); - ContentTypesCache.GetPublishedContentTypeByAlias = null; - - var publishedContent = _ctx.Content.GetById(1100); - Assert.That(publishedContent.IsDocumentType("base", true)); - } - - [Test] - public void IsDocumentType_Recursive_InvalidBaseType_ReturnsFalse() - { - InitializeInheritedContentTypes(); - - var publishedContent = _ctx.Content.GetById(1100); - Assert.That(publishedContent.IsDocumentType("invalidbase", true), Is.False); - } - - private void InitializeInheritedContentTypes() - { - _ctx = GetUmbracoContext("/", 1, null, true); - if (_createContentTypes) - { - var contentTypeService = ServiceContext.ContentTypeService; - var baseType = new ContentType(ShortStringHelper, -1) { Alias = "base", Name = "Base" }; - const string contentTypeAlias = "inherited"; - var inheritedType = new ContentType(ShortStringHelper, baseType, contentTypeAlias) { Alias = contentTypeAlias, Name = "Inherited" }; - contentTypeService.Save(baseType); - contentTypeService.Save(inheritedType); - _contentTypes = new Dictionary - { - { baseType.Alias, new PublishedContentType(baseType, null) }, - { inheritedType.Alias, new PublishedContentType(inheritedType, null) } - }; - ContentTypesCache.GetPublishedContentTypeByAlias = alias => _contentTypes[alias]; - _createContentTypes = false; - } - - ContentTypesCache.GetPublishedContentTypeByAlias = alias => _contentTypes[alias]; - - _xmlContent = @" - - -]> - - -"; - } - } -} diff --git a/tests/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs b/tests/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs deleted file mode 100644 index 5793262bf868..000000000000 --- a/tests/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs +++ /dev/null @@ -1,363 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Extensions; -using Umbraco.Tests.Testing; -using Current = Umbraco.Web.Composing.Current; - -namespace Umbraco.Tests.PublishedContent -{ - [TestFixture] - [UmbracoTest(TypeLoader = UmbracoTestOptions.TypeLoader.PerFixture)] - public class PublishedContentLanguageVariantTests : PublishedContentSnapshotTestBase - { - protected override void Compose() - { - base.Compose(); - - Builder.Services.AddUnique(GetServiceContext()); - } - - protected ServiceContext GetServiceContext() - { - var serviceContext = TestObjects.GetServiceContextMock(Factory); - MockLocalizationService(serviceContext); - return serviceContext; - } - - private static void MockLocalizationService(ServiceContext serviceContext) - { - // Set up languages. - // Spanish falls back to English and Italian to Spanish (and then to English). - // French has no fall back. - // Danish, Swedish and Norweigan create an invalid loop. - var globalSettings = new GlobalSettings(); - var languages = new List - { - new Language(globalSettings, "en-US") { Id = 1, CultureName = "English", IsDefault = true }, - new Language(globalSettings, "fr") { Id = 2, CultureName = "French" }, - new Language(globalSettings, "es") { Id = 3, CultureName = "Spanish", FallbackLanguageId = 1 }, - new Language(globalSettings, "it") { Id = 4, CultureName = "Italian", FallbackLanguageId = 3 }, - new Language(globalSettings, "de") { Id = 5, CultureName = "German" }, - new Language(globalSettings, "da") { Id = 6, CultureName = "Danish", FallbackLanguageId = 8 }, - new Language(globalSettings, "sv") { Id = 7, CultureName = "Swedish", FallbackLanguageId = 6 }, - new Language(globalSettings, "no") { Id = 8, CultureName = "Norweigan", FallbackLanguageId = 7 }, - new Language(globalSettings, "nl") { Id = 9, CultureName = "Dutch", FallbackLanguageId = 1 } - }; - - var localizationService = Mock.Get(serviceContext.LocalizationService); - localizationService.Setup(x => x.GetAllLanguages()).Returns(languages); - localizationService.Setup(x => x.GetLanguageById(It.IsAny())) - .Returns((int id) => languages.SingleOrDefault(y => y.Id == id)); - localizationService.Setup(x => x.GetLanguageByIsoCode(It.IsAny())) - .Returns((string c) => languages.SingleOrDefault(y => y.IsoCode == c)); - } - - internal override void PopulateCache(PublishedContentTypeFactory factory, SolidPublishedContentCache cache) - { - var prop1Type = factory.CreatePropertyType("prop1", 1, variations: ContentVariation.Culture); - var welcomeType = factory.CreatePropertyType("welcomeText", 1, variations: ContentVariation.Culture); - var welcome2Type = factory.CreatePropertyType("welcomeText2", 1, variations: ContentVariation.Culture); - var nopropType = factory.CreatePropertyType("noprop", 1, variations: ContentVariation.Culture); - - IEnumerable CreatePropertyTypes1(IPublishedContentType contentType) - { - yield return factory.CreatePropertyType(contentType, "prop1", 1, variations: ContentVariation.Culture); - yield return factory.CreatePropertyType(contentType, "welcomeText", 1, variations: ContentVariation.Culture); - yield return factory.CreatePropertyType(contentType, "welcomeText2", 1, variations: ContentVariation.Culture); - yield return factory.CreatePropertyType(contentType, "noprop", 1, variations: ContentVariation.Culture); - } - - var contentType1 = factory.CreateContentType(Guid.NewGuid(), 1, "ContentType1", Enumerable.Empty(), CreatePropertyTypes1); - - IEnumerable CreatePropertyTypes2(IPublishedContentType contentType) - { - yield return factory.CreatePropertyType(contentType, "prop3", 1, variations: ContentVariation.Culture); - } - - var contentType2 = factory.CreateContentType(Guid.NewGuid(), 2, "contentType2", Enumerable.Empty(), CreatePropertyTypes2); - - var prop1 = new SolidPublishedPropertyWithLanguageVariants - { - Alias = "welcomeText", - PropertyType = welcomeType - }; - prop1.SetSourceValue("en-US", "Welcome", true); - prop1.SetValue("en-US", "Welcome", true); - prop1.SetSourceValue("de", "Willkommen"); - prop1.SetValue("de", "Willkommen"); - prop1.SetSourceValue("nl", "Welkom"); - prop1.SetValue("nl", "Welkom"); - - var prop2 = new SolidPublishedPropertyWithLanguageVariants - { - Alias = "welcomeText2", - PropertyType = welcome2Type - }; - prop2.SetSourceValue("en-US", "Welcome", true); - prop2.SetValue("en-US", "Welcome", true); - - var prop3 = new SolidPublishedPropertyWithLanguageVariants - { - Alias = "welcomeText", - PropertyType = welcomeType - }; - prop3.SetSourceValue("en-US", "Welcome", true); - prop3.SetValue("en-US", "Welcome", true); - - var noprop = new SolidPublishedProperty - { - Alias = "noprop", - PropertyType = nopropType - }; - noprop.SolidHasValue = false; // has no value - noprop.SolidValue = "xxx"; // but returns something - - var item1 = new SolidPublishedContent(contentType1) - { - Id = 1, - SortOrder = 0, - Name = "Content 1", - UrlSegment = "content-1", - Path = "/1", - Level = 1, - ParentId = -1, - ChildIds = new[] { 2 }, - Properties = new Collection - { - prop1, prop2, noprop - } - }; - - var item2 = new SolidPublishedContent(contentType1) - { - Id = 2, - SortOrder = 0, - Name = "Content 2", - UrlSegment = "content-2", - Path = "/1/2", - Level = 2, - ParentId = 1, - ChildIds = new int[] { 3 }, - Properties = new Collection - { - prop3 - } - }; - - var prop4 = new SolidPublishedPropertyWithLanguageVariants - { - Alias = "prop3", - PropertyType = contentType2.GetPropertyType("prop3") - }; - prop4.SetSourceValue("en-US", "Oxxo", true); - prop4.SetValue("en-US", "Oxxo", true); - - var item3 = new SolidPublishedContent(contentType2) - { - Id = 3, - SortOrder = 0, - Name = "Content 3", - UrlSegment = "content-3", - Path = "/1/2/3", - Level = 3, - ParentId = 2, - ChildIds = new int[] { }, - Properties = new Collection - { - prop4 - } - }; - - item1.Children = new List { item2 }; - item2.Parent = item1; - - item2.Children = new List { item3 }; - item3.Parent = item2; - - cache.Add(item1); - cache.Add(item2); - cache.Add(item3); - } - - [Test] - public void Can_Get_Content_For_Populated_Requested_Language() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First(); - var value = content.Value(Mock.Of(), "welcomeText", "en-US"); - Assert.AreEqual("Welcome", value); - } - - [Test] - public void Can_Get_Content_For_Populated_Requested_Non_Default_Language() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First(); - var value = content.Value(Mock.Of(), "welcomeText", "de"); - Assert.AreEqual("Willkommen", value); - } - - [Test] - public void Do_Not_Get_Content_For_Unpopulated_Requested_Language_Without_Fallback() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First(); - var value = content.Value(Mock.Of(), "welcomeText", "fr"); - Assert.IsNull(value); - } - - [Test] - public void Do_Not_Get_Content_For_Unpopulated_Requested_Language_With_Fallback_Unless_Requested() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First(); - var value = content.Value(Mock.Of(), "welcomeText", "es"); - Assert.IsNull(value); - } - - [Test] - public void Can_Get_Content_For_Unpopulated_Requested_Language_With_Fallback() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First(); - var value = content.Value(Factory.GetRequiredService(), "welcomeText", "es", fallback: Fallback.ToLanguage); - Assert.AreEqual("Welcome", value); - } - - [Test] - public void Can_Get_Content_For_Unpopulated_Requested_Language_With_Fallback_Over_Two_Levels() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First(); - var value = content.Value(Factory.GetRequiredService(), "welcomeText", "it", fallback: Fallback.To(Fallback.Language, Fallback.Ancestors)); - Assert.AreEqual("Welcome", value); - } - - [Test] - public void Do_Not_GetContent_For_Unpopulated_Requested_Language_With_Fallback_Over_That_Loops() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First(); - var value = content.Value(Mock.Of(), "welcomeText", "no", fallback: Fallback.ToLanguage); - Assert.IsNull(value); - } - - [Test] - public void Do_Not_Get_Content_Recursively_Unless_Requested() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First().Children.First(); - var value = content.Value(Mock.Of(), "welcomeText2"); - Assert.IsNull(value); - } - - [Test] - public void Can_Get_Content_Recursively() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First().Children.First(); - var value = content.Value(Factory.GetRequiredService(), "welcomeText2", fallback: Fallback.ToAncestors); - Assert.AreEqual("Welcome", value); - } - - [Test] - public void Do_Not_Get_Content_Recursively_Unless_Requested2() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First().Children.First().Children.First(); - Assert.IsNull(content.GetProperty("welcomeText2")); - var value = content.Value(Mock.Of(), "welcomeText2"); - Assert.IsNull(value); - } - - [Test] - public void Can_Get_Content_Recursively2() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First().Children.First().Children.First(); - Assert.IsNull(content.GetProperty("welcomeText2")); - var value = content.Value(Factory.GetRequiredService(), "welcomeText2", fallback: Fallback.ToAncestors); - Assert.AreEqual("Welcome", value); - } - - [Test] - public void Can_Get_Content_Recursively3() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First().Children.First().Children.First(); - Assert.IsNull(content.GetProperty("noprop")); - var value = content.Value(Factory.GetRequiredService(), "noprop", fallback: Fallback.ToAncestors); - // property has no value but we still get the value (ie, the converter would do something) - Assert.AreEqual("xxx", value); - } - - [Test] - public void Can_Get_Content_With_Recursive_Priority() - { - Current.VariationContextAccessor.VariationContext = new VariationContext("nl"); - var content = Current.UmbracoContext.Content.GetAtRoot().First().Children.First(); - - var value = content.Value(Factory.GetRequiredService(), "welcomeText", "nl", fallback: Fallback.To(Fallback.Ancestors, Fallback.Language)); - - // No Dutch value is directly assigned. Check has fallen back to Dutch value from parent. - Assert.AreEqual("Welkom", value); - } - - [Test] - public void Can_Get_Content_With_Fallback_Language_Priority() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First().Children.First(); - var value = content.Value(Factory.GetRequiredService(), "welcomeText", "nl", fallback: Fallback.ToLanguage); - - // No Dutch value is directly assigned. Check has fallen back to English value from language variant. - Assert.AreEqual("Welcome", value); - } - - [Test] - public void Throws_For_Non_Supported_Fallback() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First().Children.First(); - Assert.Throws(() => content.Value(Factory.GetRequiredService(), "welcomeText", "nl", fallback: Fallback.To(999))); - } - - [Test] - public void Can_Fallback_To_Default_Value() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First().Children.First(); - - // no Dutch value is assigned, so getting null - var value = content.Value(Factory.GetRequiredService(), "welcomeText", "nl"); - Assert.IsNull(value); - - // even if we 'just' provide a default value - value = content.Value(Factory.GetRequiredService(), "welcomeText", "nl", defaultValue: "woop"); - Assert.IsNull(value); - - // but it works with proper fallback settings - value = content.Value(Factory.GetRequiredService(), "welcomeText", "nl", fallback: Fallback.ToDefaultValue, defaultValue: "woop"); - Assert.AreEqual("woop", value); - } - - [Test] - public void Can_Have_Custom_Default_Value() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First().Children.First(); - - // HACK: the value, pretend the converter would return something - var prop = content.GetProperty("welcomeText") as SolidPublishedPropertyWithLanguageVariants; - Assert.IsNotNull(prop); - prop.SetValue("nl", "nope"); // HasValue false but getting value returns this - - // there is an EN value - var value = content.Value(Factory.GetRequiredService(), "welcomeText", "en-US"); - Assert.AreEqual("Welcome", value); - - // there is no NL value and we get the 'converted' value - value = content.Value(Factory.GetRequiredService(), "welcomeText", "nl"); - Assert.AreEqual("nope", value); - - // but it works with proper fallback settings - value = content.Value(Factory.GetRequiredService(), "welcomeText", "nl", fallback: Fallback.ToDefaultValue, defaultValue: "woop"); - Assert.AreEqual("woop", value); - } - } -} diff --git a/tests/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs b/tests/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs deleted file mode 100644 index b592e9630d97..000000000000 --- a/tests/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs +++ /dev/null @@ -1,215 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using Examine; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Infrastructure; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Extensions; -using Umbraco.Tests.Testing; -using Umbraco.Web; -using Umbraco.Web.Composing; - -namespace Umbraco.Tests.PublishedContent -{ - [TestFixture] - [UmbracoTest(TypeLoader = UmbracoTestOptions.TypeLoader.PerFixture)] - public class PublishedContentMoreTests : PublishedContentSnapshotTestBase - { - internal override void PopulateCache(PublishedContentTypeFactory factory, SolidPublishedContentCache cache) - { - IEnumerable CreatePropertyTypes(IPublishedContentType contentType) - { - yield return factory.CreatePropertyType(contentType, "prop1", 1); - } - - var contentType1 = factory.CreateContentType(Guid.NewGuid(), 1, "ContentType1", Enumerable.Empty(), CreatePropertyTypes); - var contentType2 = factory.CreateContentType(Guid.NewGuid(), 2, "ContentType2", Enumerable.Empty(), CreatePropertyTypes); - var contentType2Sub = factory.CreateContentType(Guid.NewGuid(), 3, "ContentType2Sub", Enumerable.Empty(), CreatePropertyTypes); - - var content = new SolidPublishedContent(contentType1) - { - Id = 1, - SortOrder = 0, - Name = "Content 1", - UrlSegment = "content-1", - Path = "/1", - Level = 1, - ParentId = -1, - ChildIds = new int[] { }, - Properties = new Collection - { - new SolidPublishedProperty - { - Alias = "prop1", - SolidHasValue = true, - SolidValue = 1234, - SolidSourceValue = "1234" - } - } - }; - cache.Add(content); - - content = new SolidPublishedContent(contentType2) - { - Id = 2, - SortOrder = 1, - Name = "Content 2", - UrlSegment = "content-2", - Path = "/2", - Level = 1, - ParentId = -1, - ChildIds = new int[] { }, - Properties = new Collection - { - new SolidPublishedProperty - { - Alias = "prop1", - SolidHasValue = true, - SolidValue = 1234, - SolidSourceValue = "1234" - } - } - }; - cache.Add(content); - - content = new SolidPublishedContent(contentType2Sub) - { - Id = 3, - SortOrder = 2, - Name = "Content 2Sub", - UrlSegment = "content-2sub", - Path = "/3", - Level = 1, - ParentId = -1, - ChildIds = new int[] { }, - Properties = new Collection - { - new SolidPublishedProperty - { - Alias = "prop1", - SolidHasValue = true, - SolidValue = 1234, - SolidSourceValue = "1234" - } - } - }; - cache.Add(content); - } - - [Test] - public void First() - { - var content = Current.UmbracoContext.Content.GetAtRoot().First(); - Assert.AreEqual("Content 1", content.Name(VariationContextAccessor)); - } - - [Test] - public void Distinct() - { - var items = Current.UmbracoContext.Content.GetAtRoot() - .Distinct() - .Distinct() - .ToIndexedArray(); - - var item = items[0]; - Assert.AreEqual("Content 1", item.Content.Name); - Assert.IsTrue(item.IsFirst()); - Assert.IsFalse(item.IsLast()); - - item = items[1]; - Assert.AreEqual("Content 2", item.Content.Name); - Assert.IsFalse(item.IsFirst()); - Assert.IsFalse(item.IsLast()); - - item = items[2]; - Assert.AreEqual("Content 2Sub", item.Content.Name); - Assert.IsFalse(item.IsFirst()); - Assert.IsTrue(item.IsLast()); - } - - [Test] - public void OfType1() - { - var items = Current.UmbracoContext.Content.GetAtRoot() - .OfType() - .Distinct() - .ToIndexedArray(); - Assert.AreEqual(2, items.Length); - Assert.IsInstanceOf(items.First().Content); - } - - [Test] - public void OfType2() - { - var content = Current.UmbracoContext.Content.GetAtRoot() - .OfType() - .Distinct() - .ToIndexedArray(); - Assert.AreEqual(1, content.Length); - Assert.IsInstanceOf(content.First().Content); - } - - [Test] - public void OfType() - { - var content = Current.UmbracoContext.Content.GetAtRoot() - .OfType() - .First(x => x.Prop1 == 1234); - Assert.AreEqual("Content 2", content.Name); - Assert.AreEqual(1234, content.Prop1); - } - - [Test] - public void Position() - { - var items = Current.UmbracoContext.Content.GetAtRoot() - .Where(x => x.Value(Mock.Of(), "prop1") == 1234) - .ToIndexedArray(); - - Assert.IsTrue(items.First().IsFirst()); - Assert.IsFalse(items.First().IsLast()); - Assert.IsFalse(items.Skip(1).First().IsFirst()); - Assert.IsFalse(items.Skip(1).First().IsLast()); - Assert.IsFalse(items.Skip(2).First().IsFirst()); - Assert.IsTrue(items.Skip(2).First().IsLast()); - } - - [Test] - public void Issue() - { - var content = Current.UmbracoContext.Content.GetAtRoot() - .Distinct() - .OfType(); - - var where = content.Where(x => x.Prop1 == 1234); - var first = where.First(); - Assert.AreEqual(1234, first.Prop1); - - var content2 = Current.UmbracoContext.Content.GetAtRoot() - .OfType() - .First(x => x.Prop1 == 1234); - Assert.AreEqual(1234, content2.Prop1); - - var content3 = Current.UmbracoContext.Content.GetAtRoot() - .OfType() - .First(); - Assert.AreEqual(1234, content3.Prop1); - } - - [Test] - public void PublishedContentQueryTypedContentList() - { - var examineManager = new Mock(); - var query = new PublishedContentQuery(Current.UmbracoContext.PublishedSnapshot, Current.UmbracoContext.VariationContextAccessor, examineManager.Object); - var result = query.Content(new[] { 1, 2, 4 }).ToArray(); - Assert.AreEqual(2, result.Length); - Assert.AreEqual(1, result[0].Id); - Assert.AreEqual(2, result[1].Id); - } - } -} diff --git a/tests/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs b/tests/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs deleted file mode 100644 index e0b95f95e453..000000000000 --- a/tests/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Web.Routing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure.Serialization; -using Umbraco.Cms.Tests.Common; -using Umbraco.Extensions; -using Umbraco.Tests.TestHelpers; -using Umbraco.Web; - -namespace Umbraco.Tests.PublishedContent -{ - public abstract class PublishedContentSnapshotTestBase : PublishedContentTestBase - { - // read http://stackoverflow.com/questions/7713326/extension-method-that-works-on-ienumerablet-and-iqueryablet - // and http://msmvps.com/blogs/jon_skeet/archive/2010/10/28/overloading-and-generic-constraints.aspx - // and http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx - - public override void SetUp() - { - base.SetUp(); - - var umbracoContext = GetUmbracoContext(); - Umbraco.Web.Composing.Current.UmbracoContextAccessor.UmbracoContext = umbracoContext; - } - - protected override void Compose() - { - base.Compose(); - - Builder.Services.AddUnique(f => new PublishedModelFactory(f.GetRequiredService().GetTypes(), f.GetRequiredService())); - } - - protected override TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, ILogger logger, IProfilingLogger profilingLogger , IHostingEnvironment hostingEnvironment) - { - var baseLoader = base.CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, profilingLogger , hostingEnvironment); - - return new TypeLoader(typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, profilingLogger , false, - // this is so the model factory looks into the test assembly - baseLoader.AssembliesToScan - .Union(new[] {typeof(PublishedContentMoreTests).Assembly}) - .ToList()); - } - - private IUmbracoContext GetUmbracoContext() - { - RouteData routeData = null; - - var publishedSnapshot = CreatePublishedSnapshot(); - - var publishedSnapshotService = new Mock(); - publishedSnapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(publishedSnapshot); - - var globalSettings = TestObjects.GetGlobalSettings(); - - var httpContext = GetHttpContextFactory("http://umbraco.local/", routeData).HttpContext; - - var httpContextAccessor = TestHelper.GetHttpContextAccessor(httpContext); - var umbracoContext = new UmbracoContext( - httpContextAccessor, - publishedSnapshotService.Object, - Mock.Of(), - globalSettings, - HostingEnvironment, - new TestVariationContextAccessor(), - UriUtility, - new AspNetCookieManager(httpContextAccessor)); - - return umbracoContext; - } - - private SolidPublishedSnapshot CreatePublishedSnapshot() - { - var serializer = new ConfigurationEditorJsonSerializer(); - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(DataValueEditorFactory), serializer) { Id = 1 }); - - var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); - var caches = new SolidPublishedSnapshot(); - var cache = caches.InnerContentCache; - PopulateCache(factory, cache); - return caches; - } - - internal abstract void PopulateCache(PublishedContentTypeFactory factory, SolidPublishedContentCache cache); - } -} diff --git a/tests/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/tests/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs deleted file mode 100644 index 7befa03f45f0..000000000000 --- a/tests/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Media; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.PropertyEditors.ValueConverters; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Core.Templates; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure.Serialization; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests.PublishedContent -{ - /// - /// Abstract base class for tests for published content and published media - /// - public abstract class PublishedContentTestBase : BaseWebTest - { - protected override void Compose() - { - base.Compose(); - - // FIXME: what about the if (PropertyValueConvertersResolver.HasCurrent == false) ?? - // can we risk double - registering and then, what happens? - - Builder.WithCollectionBuilder() - .Clear() - .Append() - .Append() - .Append(); - } - - protected override void Initialize() - { - base.Initialize(); - - var converters = Factory.GetRequiredService(); - var umbracoContextAccessor = Mock.Of(); - var publishedUrlProvider = Mock.Of(); - var loggerFactory = NullLoggerFactory.Instance; - var serializer = new ConfigurationEditorJsonSerializer(); - - var imageSourceParser = new HtmlImageSourceParser(publishedUrlProvider); - var mediaFileManager = new MediaFileManager(Mock.Of(), Mock.Of(), - loggerFactory.CreateLogger(), Mock.Of()); - var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, loggerFactory.CreateLogger(), HostingEnvironment, Mock.Of(), Mock.Of(), mediaFileManager, ShortStringHelper, publishedUrlProvider, serializer); - var localLinkParser = new HtmlLocalLinkParser(umbracoContextAccessor, publishedUrlProvider); - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new RichTextPropertyEditor( - DataValueEditorFactory, - Mock.Of(), - imageSourceParser, - localLinkParser, - pastedImages, - IOHelper, - Mock.Of()), - serializer) { Id = 1 }); - - - var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeService); - - IEnumerable CreatePropertyTypes(IPublishedContentType contentType) - { - yield return publishedContentTypeFactory.CreatePropertyType(contentType, "content", 1); - } - - var type = new AutoPublishedContentType(Guid.NewGuid(), 0, "anything", CreatePropertyTypes); - ContentTypesCache.GetPublishedContentTypeByAlias = alias => type; - - var umbracoContext = GetUmbracoContext("/test"); - Umbraco.Web.Composing.Current.UmbracoContextAccessor.UmbracoContext = umbracoContext; - } - } -} diff --git a/tests/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/tests/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs deleted file mode 100644 index 15a867a7d8ca..000000000000 --- a/tests/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ /dev/null @@ -1,511 +0,0 @@ -using System.Linq; -using System.Threading; -using System.Xml; -using System.Xml.Linq; -using System.Xml.XPath; -using Microsoft.Extensions.DependencyInjection; -using Examine; -using NUnit.Framework; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.Membership; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure.Examine; -using Umbraco.Cms.Tests.Common; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Extensions; -using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.TestHelpers.Entities; - - -namespace Umbraco.Tests.PublishedContent -{ - /// - /// Tests the typed extension methods on IPublishedContent using the DefaultPublishedMediaStore - /// - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true)] - public class PublishedMediaTests : PublishedContentTestBase - { - /// - /// sets up resolvers before resolution is frozen - /// - protected override void Compose() - { - base.Compose(); - - Builder.WithCollectionBuilder() - .Clear() - .Append(); - - Builder.Services.AddUnique(); - } - - private IMediaType MakeNewMediaType(IUser user, string text, int parentId = -1) - { - var mt = new MediaType(ShortStringHelper, parentId) { Name = text, Alias = text, Thumbnail = "icon-folder", Icon = "icon-folder" }; - ServiceContext.MediaTypeService.Save(mt); - return mt; - } - - private IMedia MakeNewMedia(string name, IMediaType mediaType, IUser user, int parentId) - { - var m = ServiceContext.MediaService.CreateMediaWithIdentity(name, parentId, mediaType.Alias); - return m; - } - - /// - /// Shared with PublishMediaStoreTests - /// - /// - /// - /// - internal IPublishedContent GetNode(int id, IUmbracoContext umbracoContext) - { - var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null, HostingEnvironment), - ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, - Factory.GetRequiredService(), Factory.GetRequiredService(), VariationContextAccessor); - var doc = cache.GetById(id); - Assert.IsNotNull(doc); - return doc; - } - - private IPublishedContent GetNode(int id) - { - return GetNode(id, GetUmbracoContext("/test")); - } - - [Test] - public void Get_Property_Value_Uses_Converter() - { - var mType = MockedContentTypes.CreateImageMediaType("image2"); - //lets add an RTE to this - mType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, "test", ValueStorageType.Nvarchar, "content") - { - Name = "Rich Text", - DataTypeId = -87 //tiny mce - }); - var existing = ServiceContext.MediaTypeService.GetAll(); - ServiceContext.MediaTypeService.Save(mType); - var media = MockedMedia.CreateMediaImage(mType, -1); - media.Properties["content"].SetValue("
        This is some content
        "); - ServiceContext.MediaService.Save(media); - - var publishedMedia = GetNode(media.Id); - - var propVal = publishedMedia.Value(Factory.GetRequiredService(), "content"); - Assert.IsInstanceOf(propVal); - Assert.AreEqual("
        This is some content
        ", propVal.ToString()); - - var propVal2 = publishedMedia.Value(Factory.GetRequiredService(), "content"); - Assert.IsInstanceOf(propVal2); - Assert.AreEqual("
        This is some content
        ", propVal2.ToString()); - - var propVal3 = publishedMedia.Value(Factory.GetRequiredService(), "Content"); - Assert.IsInstanceOf(propVal3); - Assert.AreEqual("
        This is some content
        ", propVal3.ToString()); - } - - [Test] - public void Ensure_Children_Sorted_With_Examine() - { - var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetRequiredService(), IndexInitializer.GetMockMediaService()); - - using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, HostingEnvironment, RuntimeState, luceneDir, - validator: new ContentValueSetValidator(true))) - using (indexer.ProcessNonAsync()) - { - rebuilder.RegisterIndex(indexer.Name); - rebuilder.Populate(indexer); - - var searcher = indexer.GetSearcher(); - var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryAppCache(), ContentTypesCache, Factory.GetRequiredService(), Factory.GetRequiredService()); - - //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace - var publishedMedia = cache.GetById(1111); - var rootChildren = publishedMedia.Children(VariationContextAccessor).ToArray(); - var currSort = 0; - for (var i = 0; i < rootChildren.Count(); i++) - { - Assert.GreaterOrEqual(rootChildren[i].SortOrder, currSort); - currSort = rootChildren[i].SortOrder; - } - } - } - - [Test] - public void Do_Not_Find_In_Recycle_Bin() - { - var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetRequiredService(), IndexInitializer.GetMockMediaService()); - - using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, HostingEnvironment, RuntimeState, luceneDir, - //include unpublished content since this uses the 'internal' indexer, it's up to the media cache to filter - validator: new ContentValueSetValidator(false))) - using (indexer.ProcessNonAsync()) - { - rebuilder.RegisterIndex(indexer.Name); - rebuilder.Populate(indexer); - - var searcher = indexer.GetSearcher(); - var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryAppCache(), ContentTypesCache, Factory.GetRequiredService(), Factory.GetRequiredService()); - - //ensure it is found - var publishedMedia = cache.GetById(3113); - Assert.IsNotNull(publishedMedia); - - //move item to recycle bin - var newXml = XElement.Parse(@" - - 115 - 268 - 10726 - jpg - "); - indexer.IndexItems(new[]{ newXml.ConvertToValueSet("media") }); - - - //ensure it still exists in the index (raw examine search) - var criteria = searcher.CreateQuery(); - var filter = criteria.Id(3113); - var found = filter.Execute(); - Assert.IsNotNull(found); - Assert.AreEqual(1, found.TotalItemCount); - - //ensure it does not show up in the published media store - var recycledMedia = cache.GetById(3113); - Assert.IsNull(recycledMedia); - - } - - } - - [Test] - public void Children_With_Examine() - { - var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetRequiredService(), IndexInitializer.GetMockMediaService()); - - using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, HostingEnvironment, RuntimeState, luceneDir, - validator: new ContentValueSetValidator(true))) - using (indexer.ProcessNonAsync()) - { - rebuilder.RegisterIndex(indexer.Name); - rebuilder.Populate(indexer); - - var searcher = indexer.GetSearcher(); - var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryAppCache(), ContentTypesCache, Factory.GetRequiredService(), Factory.GetRequiredService()); - - //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace - var publishedMedia = cache.GetById(1111); - var rootChildren = publishedMedia.Children(VariationContextAccessor); - Assert.IsTrue(rootChildren.Select(x => x.Id).ContainsAll(new[] { 2222, 1113, 1114, 1115, 1116 })); - - var publishedChild1 = cache.GetById(2222); - var subChildren = publishedChild1.Children(VariationContextAccessor); - Assert.IsTrue(subChildren.Select(x => x.Id).ContainsAll(new[] { 2112 })); - } - } - - [Test] - public void Descendants_With_Examine() - { - var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetRequiredService(), IndexInitializer.GetMockMediaService()); - - using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, HostingEnvironment, RuntimeState, luceneDir, - validator: new ContentValueSetValidator(true))) - using (indexer.ProcessNonAsync()) - { - rebuilder.RegisterIndex(indexer.Name); - rebuilder.Populate(indexer); - - var searcher = indexer.GetSearcher(); - var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryAppCache(), ContentTypesCache, Factory.GetRequiredService(), Factory.GetRequiredService()); - - //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace - var publishedMedia = cache.GetById(1111); - var rootDescendants = publishedMedia.Descendants(Factory.GetRequiredService()); - Assert.IsTrue(rootDescendants.Select(x => x.Id).ContainsAll(new[] { 2112, 2222, 1113, 1114, 1115, 1116 })); - - var publishedChild1 = cache.GetById(2222); - var subDescendants = publishedChild1.Descendants(Factory.GetRequiredService()); - Assert.IsTrue(subDescendants.Select(x => x.Id).ContainsAll(new[] { 2112, 3113 })); - } - } - - [Test] - public void DescendantsOrSelf_With_Examine() - { - var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetRequiredService(), IndexInitializer.GetMockMediaService()); - - using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, HostingEnvironment, RuntimeState, luceneDir, - validator: new ContentValueSetValidator(true))) - using (indexer.ProcessNonAsync()) - { - rebuilder.RegisterIndex(indexer.Name); - rebuilder.Populate(indexer); - - var searcher = indexer.GetSearcher(); - var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryAppCache(), ContentTypesCache, Factory.GetRequiredService(), Factory.GetRequiredService()); - - //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace - var publishedMedia = cache.GetById(1111); - var rootDescendants = publishedMedia.DescendantsOrSelf(Factory.GetRequiredService()); - Assert.IsTrue(rootDescendants.Select(x => x.Id).ContainsAll(new[] { 1111, 2112, 2222, 1113, 1114, 1115, 1116 })); - - var publishedChild1 = cache.GetById(2222); - var subDescendants = publishedChild1.DescendantsOrSelf(Factory.GetRequiredService()); - Assert.IsTrue(subDescendants.Select(x => x.Id).ContainsAll(new[] { 2222, 2112, 3113 })); - } - } - - [Test] - public void Ancestors_With_Examine() - { - var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetRequiredService(), IndexInitializer.GetMockMediaService()); - - - using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, HostingEnvironment, RuntimeState, luceneDir, - validator: new ContentValueSetValidator(true))) - using (indexer.ProcessNonAsync()) - { - rebuilder.RegisterIndex(indexer.Name); - rebuilder.Populate(indexer); - - var ctx = GetUmbracoContext("/test"); - var searcher = indexer.GetSearcher(); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryAppCache(), ContentTypesCache, Factory.GetRequiredService(), Factory.GetRequiredService()); - - //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace - var publishedMedia = cache.GetById(3113); - var ancestors = publishedMedia.Ancestors(); - Assert.IsTrue(ancestors.Select(x => x.Id).ContainsAll(new[] { 2112, 2222, 1111 })); - } - - } - - [Test] - public void AncestorsOrSelf_With_Examine() - { - var rebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetRequiredService(), IndexInitializer.GetMockMediaService()); - - using (var luceneDir = new RandomIdRamDirectory()) - using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, HostingEnvironment, RuntimeState, luceneDir, - validator: new ContentValueSetValidator(true))) - using (indexer.ProcessNonAsync()) - { - rebuilder.RegisterIndex(indexer.Name); - rebuilder.Populate(indexer); - - - var ctx = GetUmbracoContext("/test"); - var searcher = indexer.GetSearcher(); - var cache = new PublishedMediaCache(ServiceContext.MediaService, ServiceContext.UserService, searcher, new DictionaryAppCache(), ContentTypesCache, Factory.GetRequiredService(), Factory.GetRequiredService()); - - //we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace - var publishedMedia = cache.GetById(3113); - var ancestors = publishedMedia.AncestorsOrSelf(); - Assert.IsTrue(ancestors.Select(x => x.Id).ContainsAll(new[] { 3113, 2112, 2222, 1111 })); - } - } - - [Test] - public void Children_Without_Examine() - { - var user = ServiceContext.UserService.GetUserById(0); - var mType = MakeNewMediaType(user, "TestMediaType"); - var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); - - var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); - var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); - var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); - - var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); - var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); - var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); - - var publishedMedia = GetNode(mRoot.Id); - var rootChildren = publishedMedia.Children(VariationContextAccessor); - Assert.IsTrue(rootChildren.Select(x => x.Id).ContainsAll(new[] { mChild1.Id, mChild2.Id, mChild3.Id })); - - var publishedChild1 = GetNode(mChild1.Id); - var subChildren = publishedChild1.Children(VariationContextAccessor); - Assert.IsTrue(subChildren.Select(x => x.Id).ContainsAll(new[] { mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); - } - - [Test] - public void Descendants_Without_Examine() - { - var user = ServiceContext.UserService.GetUserById(0); - var mType = MakeNewMediaType(user, "TestMediaType"); - var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); - - var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); - var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); - var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); - - var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); - var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); - var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); - - var publishedMedia = GetNode(mRoot.Id); - var rootDescendants = publishedMedia.Descendants(Factory.GetRequiredService()); - Assert.IsTrue(rootDescendants.Select(x => x.Id).ContainsAll(new[] { mChild1.Id, mChild2.Id, mChild3.Id, mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); - - var publishedChild1 = GetNode(mChild1.Id); - var subDescendants = publishedChild1.Descendants(Factory.GetRequiredService()); - Assert.IsTrue(subDescendants.Select(x => x.Id).ContainsAll(new[] { mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); - } - - [Test] - public void DescendantsOrSelf_Without_Examine() - { - var user = ServiceContext.UserService.GetUserById(0); - var mType = MakeNewMediaType(user, "TestMediaType"); - var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); - - var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); - var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); - var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); - - var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); - var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); - var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); - - var publishedMedia = GetNode(mRoot.Id); - var rootDescendantsOrSelf = publishedMedia.DescendantsOrSelf(Factory.GetRequiredService()); - Assert.IsTrue(rootDescendantsOrSelf.Select(x => x.Id).ContainsAll( - new[] { mRoot.Id, mChild1.Id, mChild2.Id, mChild3.Id, mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); - - var publishedChild1 = GetNode(mChild1.Id); - var subDescendantsOrSelf = publishedChild1.DescendantsOrSelf(Factory.GetRequiredService()); - Assert.IsTrue(subDescendantsOrSelf.Select(x => x.Id).ContainsAll( - new[] { mChild1.Id, mSubChild1.Id, mSubChild2.Id, mSubChild3.Id })); - } - - [Test] - public void Parent_Without_Examine() - { - var user = ServiceContext.UserService.GetUserById(0); - var mType = MakeNewMediaType(user, "TestMediaType"); - var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); - - var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); - var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); - var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); - - var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); - var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); - var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); - - var publishedRoot = GetNode(mRoot.Id); - Assert.AreEqual(null, publishedRoot.Parent); - - var publishedChild1 = GetNode(mChild1.Id); - Assert.AreEqual(mRoot.Id, publishedChild1.Parent.Id); - - var publishedSubChild1 = GetNode(mSubChild1.Id); - Assert.AreEqual(mChild1.Id, publishedSubChild1.Parent.Id); - } - - [Test] - public void Ancestors_Without_Examine() - { - var user = ServiceContext.UserService.GetUserById(0); - var mType = MakeNewMediaType(user, "TestMediaType"); - var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); - - var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); - var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); - var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); - - var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); - var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); - var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); - - var publishedSubChild1 = GetNode(mSubChild1.Id); - Assert.IsTrue(publishedSubChild1.Ancestors().Select(x => x.Id).ContainsAll(new[] { mChild1.Id, mRoot.Id })); - } - - [Test] - public void AncestorsOrSelf_Without_Examine() - { - var user = ServiceContext.UserService.GetUserById(0); - var mType = MakeNewMediaType(user, "TestMediaType"); - var mRoot = MakeNewMedia("MediaRoot", mType, user, -1); - - var mChild1 = MakeNewMedia("Child1", mType, user, mRoot.Id); - var mChild2 = MakeNewMedia("Child2", mType, user, mRoot.Id); - var mChild3 = MakeNewMedia("Child3", mType, user, mRoot.Id); - - var mSubChild1 = MakeNewMedia("SubChild1", mType, user, mChild1.Id); - var mSubChild2 = MakeNewMedia("SubChild2", mType, user, mChild1.Id); - var mSubChild3 = MakeNewMedia("SubChild3", mType, user, mChild1.Id); - - var publishedSubChild1 = GetNode(mSubChild1.Id); - Assert.IsTrue(publishedSubChild1.AncestorsOrSelf().Select(x => x.Id).ContainsAll( - new[] { mSubChild1.Id, mChild1.Id, mRoot.Id })); - } - - [Test] - public void Convert_From_Standard_Xml() - { - var nodeId = 2112; - - var xml = XElement.Parse(@" - - 115 - 268 - 10726 - jpg - - - 115 - 268 - 10726 - jpg - - "); - var node = xml.DescendantsAndSelf("Image").Single(x => (int)x.Attribute("id") == nodeId); - - var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null, HostingEnvironment), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetRequiredService(), Factory.GetRequiredService(), VariationContextAccessor); - - var nav = node.CreateNavigator(); - - var converted = publishedMedia.CreateFromCacheValues( - publishedMedia.ConvertFromXPathNodeIterator(nav.Select("/Image"), nodeId)); - - Assert.AreEqual(nodeId, converted.Id); - Assert.AreEqual(3, converted.Level); - Assert.AreEqual(1, converted.SortOrder); - Assert.AreEqual("Sam's Umbraco Image", converted.Name); - Assert.AreEqual("-1,1111,2222,2112", converted.Path); - } - - [Test] - public void Detects_Error_In_Xml() - { - var errorXml = new XElement("error", string.Format("No media is maching '{0}'", 1234)); - var nav = errorXml.CreateNavigator(); - - var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null, HostingEnvironment), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetRequiredService(), Factory.GetRequiredService(), VariationContextAccessor); - var converted = publishedMedia.ConvertFromXPathNodeIterator(nav.Select("/"), 1234); - - Assert.IsNull(converted); - } - } -} diff --git a/tests/Umbraco.Tests/PublishedContent/PublishedRouterTests.cs b/tests/Umbraco.Tests/PublishedContent/PublishedRouterTests.cs deleted file mode 100644 index e59043e087f2..000000000000 --- a/tests/Umbraco.Tests/PublishedContent/PublishedRouterTests.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Collections.ObjectModel; -using System.Linq; -using System.Threading.Tasks; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Routing; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests.PublishedContent -{ - [TestFixture] - public class PublishedRouterTests : BaseWebTest - { - [Test] - public async Task ConfigureRequest_Returns_False_Without_HasPublishedContent() - { - var umbracoContext = GetUmbracoContext("/test"); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext)); - var request = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); - var result = publishedRouter.BuildRequest(request); - - Assert.IsFalse(result.Success()); - } - - [Test] - public async Task ConfigureRequest_Returns_False_When_IsRedirect() - { - var umbracoContext = GetUmbracoContext("/test"); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext)); - var request = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); - var content = GetPublishedContentMock(); - request.SetPublishedContent(content.Object); - request.SetCulture("en-AU"); - request.SetRedirect("/hello"); - var result = publishedRouter.BuildRequest(request); - - Assert.IsFalse(result.Success()); - } - - private Mock GetPublishedContentMock() - { - var pc = new Mock(); - pc.Setup(content => content.Id).Returns(1); - pc.Setup(content => content.Name).Returns("test"); - pc.Setup(content => content.CreateDate).Returns(DateTime.Now); - pc.Setup(content => content.UpdateDate).Returns(DateTime.Now); - pc.Setup(content => content.Path).Returns("-1,1"); - pc.Setup(content => content.Parent).Returns(() => null); - pc.Setup(content => content.Properties).Returns(new Collection()); - pc.Setup(content => content.ContentType).Returns(new PublishedContentType(Guid.NewGuid(), 22, "anything", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing)); - return pc; - } - } -} diff --git a/tests/Umbraco.Tests/PublishedContent/RootNodeTests.cs b/tests/Umbraco.Tests/PublishedContent/RootNodeTests.cs deleted file mode 100644 index 4aad3d0acbd9..000000000000 --- a/tests/Umbraco.Tests/PublishedContent/RootNodeTests.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Linq; -using NUnit.Framework; -using Umbraco.Web; - -namespace Umbraco.Tests.PublishedContent -{ - [TestFixture] - public class RootNodeTests : PublishedContentTestBase - { - [Test] - public void PublishedContentHasNoRootNode() - { - var ctx = GetUmbracoContext("/test"); - - // there is no content node with ID -1 - var content = ctx.Content.GetById(-1); - Assert.IsNull(content); - - // content at root has null parent - content = ctx.Content.GetById(1046); - Assert.IsNotNull(content); - Assert.AreEqual(1, content.Level); - Assert.IsNull(content.Parent); - - // non-existing content is null - content = ctx.Content.GetById(666); - Assert.IsNull(content); - } - - } -} diff --git a/tests/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs b/tests/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs deleted file mode 100644 index 4b2d999ce360..000000000000 --- a/tests/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs +++ /dev/null @@ -1,449 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Core.Xml; -using Umbraco.Cms.Infrastructure.Serialization; -using Umbraco.Extensions; -using Umbraco.Web.Composing; - -namespace Umbraco.Tests.PublishedContent -{ - public class SolidPublishedSnapshot : IPublishedSnapshot - { - public readonly SolidPublishedContentCache InnerContentCache = new SolidPublishedContentCache(); - public readonly SolidPublishedContentCache InnerMediaCache = new SolidPublishedContentCache(); - - public IPublishedContentCache Content => InnerContentCache; - - public IPublishedMediaCache Media => InnerMediaCache; - - public IPublishedMemberCache Members => null; - - public IDomainCache Domains => null; - - public IDisposable ForcedPreview(bool forcedPreview, Action callback = null) - { - throw new NotImplementedException(); - } - - public void Resync() - { } - - public IAppCache SnapshotCache => null; - - public IAppCache ElementsCache => null; - - public void Dispose() - { } - } - - public class SolidPublishedContentCache : PublishedCacheBase, IPublishedContentCache, IPublishedMediaCache - { - private readonly Dictionary _content = new Dictionary(); - - public SolidPublishedContentCache() - : base(false) - { } - - public void Add(SolidPublishedContent content) - { - _content[content.Id] = content.CreateModel(Current.PublishedModelFactory); - } - - public void Clear() - { - _content.Clear(); - } - - public IPublishedContent GetByRoute(bool preview, string route, bool? hideTopLevelNode = null, string culture = null) - { - throw new NotImplementedException(); - } - - public IPublishedContent GetByRoute(string route, bool? hideTopLevelNode = null, string culture = null) - { - throw new NotImplementedException(); - } - - public string GetRouteById(bool preview, int contentId, string culture = null) - { - throw new NotImplementedException(); - } - - public string GetRouteById(int contentId, string culture = null) - { - throw new NotImplementedException(); - } - - public override IPublishedContent GetById(bool preview, int contentId) - { - return _content.ContainsKey(contentId) ? _content[contentId] : null; - } - - public override IPublishedContent GetById(bool preview, Guid contentId) - { - throw new NotImplementedException(); - } - - public override IPublishedContent GetById(bool preview, Udi nodeId) - => throw new NotSupportedException(); - - public override bool HasById(bool preview, int contentId) - { - return _content.ContainsKey(contentId); - } - - public override IEnumerable GetAtRoot(bool preview, string culture = null) - { - return _content.Values.Where(x => x.Parent == null); - } - - public override IPublishedContent GetSingleByXPath(bool preview, string xpath, XPathVariable[] vars) - { - throw new NotImplementedException(); - } - - public override IPublishedContent GetSingleByXPath(bool preview, System.Xml.XPath.XPathExpression xpath, XPathVariable[] vars) - { - throw new NotImplementedException(); - } - - public override IEnumerable GetByXPath(bool preview, string xpath, XPathVariable[] vars) - { - throw new NotImplementedException(); - } - - public override IEnumerable GetByXPath(bool preview, System.Xml.XPath.XPathExpression xpath, XPathVariable[] vars) - { - throw new NotImplementedException(); - } - - public override System.Xml.XPath.XPathNavigator CreateNavigator(bool preview) - { - throw new NotImplementedException(); - } - - public override System.Xml.XPath.XPathNavigator CreateNodeNavigator(int id, bool preview) - { - throw new NotImplementedException(); - } - - public override bool HasContent(bool preview) - { - return _content.Count > 0; - } - - public override IPublishedContentType GetContentType(int id) - { - throw new NotImplementedException(); - } - - public override IPublishedContentType GetContentType(string alias) - { - throw new NotImplementedException(); - } - - public override IPublishedContentType GetContentType(Guid key) - { - throw new NotImplementedException(); - } - - public override IEnumerable GetByContentType(IPublishedContentType contentType) - { - throw new NotImplementedException(); - } - } - - public class SolidPublishedContent : IPublishedContent - { - #region Constructor - - public SolidPublishedContent(IPublishedContentType contentType) - { - // initialize boring stuff - TemplateId = 0; - WriterId = CreatorId = 0; - CreateDate = UpdateDate = DateTime.Now; - Version = Guid.Empty; - - ContentType = contentType; - } - - #endregion - - #region Content - - private Dictionary _cultures; - - private Dictionary GetCultures() - { - return new Dictionary { { "", new PublishedCultureInfo("", Name, UrlSegment, UpdateDate) } }; - } - - public int Id { get; set; } - public Guid Key { get; set; } - public int? TemplateId { get; set; } - public int SortOrder { get; set; } - public string Name { get; set; } - public IReadOnlyDictionary Cultures => _cultures ?? (_cultures = GetCultures()); - public string UrlSegment { get; set; } - public int WriterId { get; set; } - public int CreatorId { get; set; } - public string Path { get; set; } - public DateTime CreateDate { get; set; } - public DateTime UpdateDate { get; set; } - public Guid Version { get; set; } - public int Level { get; set; } - - public PublishedItemType ItemType => PublishedItemType.Content; - public bool IsDraft(string culture = null) => false; - public bool IsPublished(string culture = null) => true; - - #endregion - - #region Tree - - public int ParentId { get; set; } - public IEnumerable ChildIds { get; set; } - - public IPublishedContent Parent { get; set; } - public IEnumerable Children { get; set; } - public IEnumerable ChildrenForAllCultures => Children; - - #endregion - - #region ContentType - - public IPublishedContentType ContentType { get; set; } - - #endregion - - #region Properties - - public IEnumerable Properties { get; set; } - - public IPublishedProperty GetProperty(string alias) - { - return Properties.FirstOrDefault(p => p.Alias.InvariantEquals(alias)); - } - - public IPublishedProperty GetProperty(string alias, bool recurse) - { - var property = GetProperty(alias); - if (recurse == false) return property; - - IPublishedContent content = this; - while (content != null && (property == null || property.HasValue() == false)) - { - content = content.Parent; - property = content?.GetProperty(alias); - } - - return property; - } - - public object this[string alias] - { - get - { - var property = GetProperty(alias); - return property == null || property.HasValue() == false ? null : property.GetValue(); - } - } - - #endregion - } - - public class SolidPublishedProperty : IPublishedProperty - { - public IPublishedPropertyType PropertyType { get; set; } - public string Alias { get; set; } - public object SolidSourceValue { get; set; } - public object SolidValue { get; set; } - public bool SolidHasValue { get; set; } - public object SolidXPathValue { get; set; } - - public virtual object GetSourceValue(string culture = null, string segment = null) => SolidSourceValue; - public virtual object GetValue(string culture = null, string segment = null) => SolidValue; - public virtual object GetXPathValue(string culture = null, string segment = null) => SolidXPathValue; - public virtual bool HasValue(string culture = null, string segment = null) => SolidHasValue; - } - - public class SolidPublishedPropertyWithLanguageVariants : SolidPublishedProperty - { - private readonly IDictionary _solidSourceValues = new Dictionary(); - private readonly IDictionary _solidValues = new Dictionary(); - private readonly IDictionary _solidXPathValues = new Dictionary(); - - public override object GetSourceValue(string culture = null, string segment = null) - { - if (string.IsNullOrEmpty(culture)) - { - return base.GetSourceValue(culture, segment); - } - - return _solidSourceValues.ContainsKey(culture) ? _solidSourceValues[culture] : null; - } - - public override object GetValue(string culture = null, string segment = null) - { - if (string.IsNullOrEmpty(culture)) - { - return base.GetValue(culture, segment); - } - - return _solidValues.ContainsKey(culture) ? _solidValues[culture] : null; - } - - public override object GetXPathValue(string culture = null, string segment = null) - { - if (string.IsNullOrEmpty(culture)) - { - return base.GetXPathValue(culture, segment); - } - - return _solidXPathValues.ContainsKey(culture) ? _solidXPathValues[culture] : null; - } - - public override bool HasValue(string culture = null, string segment = null) - { - if (string.IsNullOrEmpty(culture)) - { - return base.HasValue(culture, segment); - } - - return _solidSourceValues.ContainsKey(culture); - } - - public void SetSourceValue(string culture, object value, bool defaultValue = false) - { - _solidSourceValues.Add(culture, value); - if (defaultValue) - { - SolidSourceValue = value; - SolidHasValue = true; - } - } - - public void SetValue(string culture, object value, bool defaultValue = false) - { - _solidValues.Add(culture, value); - if (defaultValue) - { - SolidValue = value; - SolidHasValue = true; - } - } - - public void SetXPathValue(string culture, object value, bool defaultValue = false) - { - _solidXPathValues.Add(culture, value); - if (defaultValue) - { - SolidXPathValue = value; - } - } - } - - [PublishedModel("ContentType2")] - public class ContentType2 : PublishedContentModel - { - #region Plumbing - - public ContentType2(IPublishedContent content, IPublishedValueFallback fallback) - : base(content, fallback) - { } - - #endregion - - public int Prop1 => this.Value(Mock.Of(), "prop1"); - } - - [PublishedModel("ContentType2Sub")] - public class ContentType2Sub : ContentType2 - { - #region Plumbing - - public ContentType2Sub(IPublishedContent content, IPublishedValueFallback fallback) - : base(content, fallback) - { } - - #endregion - } - - public class PublishedContentStrong1 : PublishedContentModel - { - public PublishedContentStrong1(IPublishedContent content, IPublishedValueFallback fallback) - : base(content, fallback) - { } - - public int StrongValue => this.Value(Mock.Of(), "strongValue"); - } - - public class PublishedContentStrong1Sub : PublishedContentStrong1 - { - public PublishedContentStrong1Sub(IPublishedContent content, IPublishedValueFallback fallback) - : base(content, fallback) - { } - - public int AnotherValue => this.Value(Mock.Of(), "anotherValue"); - } - - public class PublishedContentStrong2 : PublishedContentModel - { - public PublishedContentStrong2(IPublishedContent content, IPublishedValueFallback fallback) - : base(content, fallback) - { } - - public int StrongValue => this.Value(Mock.Of(), "strongValue"); - } - - public class AutoPublishedContentType : PublishedContentType - { - private static readonly IPublishedPropertyType Default; - - static AutoPublishedContentType() - { - var serializer = new ConfigurationEditorJsonSerializer(); - var dataTypeServiceMock = new Mock(); - var dataType = new DataType(new VoidEditor(Mock.Of()), serializer) - { Id = 666 }; - dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); - - var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeServiceMock.Object); - Default = factory.CreatePropertyType("*", 666); - } - - public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable propertyTypes) - : base(key, id, alias, PublishedItemType.Content, Enumerable.Empty(), propertyTypes, ContentVariation.Nothing) - { } - - public AutoPublishedContentType(Guid key, int id, string alias, Func> propertyTypes) - : base(key, id, alias, PublishedItemType.Content, Enumerable.Empty(), propertyTypes, ContentVariation.Nothing) - { } - - public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable compositionAliases, IEnumerable propertyTypes) - : base(key, id, alias, PublishedItemType.Content, compositionAliases, propertyTypes, ContentVariation.Nothing) - { } - - public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable compositionAliases, Func> propertyTypes) - : base(key, id, alias, PublishedItemType.Content, compositionAliases, propertyTypes, ContentVariation.Nothing) - { } - - public override IPublishedPropertyType GetPropertyType(string alias) - { - var propertyType = base.GetPropertyType(alias); - return propertyType ?? Default; - } - } -} diff --git a/tests/Umbraco.Tests/PublishedContent/StronglyTypedModels/Home.cs b/tests/Umbraco.Tests/PublishedContent/StronglyTypedModels/Home.cs deleted file mode 100644 index d9a3807c2599..000000000000 --- a/tests/Umbraco.Tests/PublishedContent/StronglyTypedModels/Home.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Web; -using Umbraco.Core.Models; - -namespace Umbraco.Tests.PublishedContent.StronglyTypedModels -{ - /// - /// Used for testing strongly-typed published content extensions that work against the - /// - public class Home : TypedModelBase - { - public Home(IPublishedContent publishedContent) : base(publishedContent) - { - } - } -} diff --git a/tests/Umbraco.Tests/Routing/ContentFinderByIdTests.cs b/tests/Umbraco.Tests/Routing/ContentFinderByIdTests.cs deleted file mode 100644 index 652706377caa..000000000000 --- a/tests/Umbraco.Tests/Routing/ContentFinderByIdTests.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using NUnit.Framework; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Web; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests.Routing -{ - [TestFixture] - public class ContentFinderByIdTests : BaseWebTest - { - [TestCase("/1046", 1046)] - [TestCase("/1046.aspx", 1046)] - public async Task Lookup_By_Id(string urlAsString, int nodeMatch) - { - var umbracoContext = GetUmbracoContext(urlAsString); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext)); - var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); - var webRoutingSettings = new WebRoutingSettings(); - var lookup = new ContentFinderByIdPath(Microsoft.Extensions.Options.Options.Create(webRoutingSettings), LoggerFactory.CreateLogger(), Factory.GetRequiredService(), GetUmbracoContextAccessor(umbracoContext)); - - - var result = lookup.TryFindContent(frequest); - - Assert.IsTrue(result); - Assert.AreEqual(frequest.PublishedContent.Id, nodeMatch); - } - } -} diff --git a/tests/Umbraco.Tests/Routing/ContentFinderByPageIdQueryTests.cs b/tests/Umbraco.Tests/Routing/ContentFinderByPageIdQueryTests.cs deleted file mode 100644 index 6372dc74248e..000000000000 --- a/tests/Umbraco.Tests/Routing/ContentFinderByPageIdQueryTests.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Threading.Tasks; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Web; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests.Routing -{ - [TestFixture] - public class ContentFinderByPageIdQueryTests : BaseWebTest - { - [TestCase("/?umbPageId=1046", 1046)] - [TestCase("/?UMBPAGEID=1046", 1046)] - [TestCase("/default.aspx?umbPageId=1046", 1046)] // TODO: Should this match?? - [TestCase("/some/other/page?umbPageId=1046", 1046)] // TODO: Should this match?? - [TestCase("/some/other/page.aspx?umbPageId=1046", 1046)] // TODO: Should this match?? - public async Task Lookup_By_Page_Id(string urlAsString, int nodeMatch) - { - var umbracoContext = GetUmbracoContext(urlAsString); - var httpContext = GetHttpContextFactory(urlAsString).HttpContext; - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext)); - var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); - var mockRequestAccessor = new Mock(); - mockRequestAccessor.Setup(x => x.GetRequestValue("umbPageID")).Returns(httpContext.Request.QueryString["umbPageID"]); - - var lookup = new ContentFinderByPageIdQuery(mockRequestAccessor.Object, GetUmbracoContextAccessor(umbracoContext)); - - var result = lookup.TryFindContent(frequest); - - Assert.IsTrue(result); - Assert.AreEqual(frequest.PublishedContent.Id, nodeMatch); - } - } -} diff --git a/tests/Umbraco.Tests/Routing/ContentFinderByUrlAndTemplateTests.cs b/tests/Umbraco.Tests/Routing/ContentFinderByUrlAndTemplateTests.cs deleted file mode 100644 index a7d256c9ed65..000000000000 --- a/tests/Umbraco.Tests/Routing/ContentFinderByUrlAndTemplateTests.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using NUnit.Framework; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests.Routing -{ - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class ContentFinderByUrlAndTemplateTests : BaseWebTest - { - Template CreateTemplate(string alias) - { - var template = new Template(ShortStringHelper, alias, alias); - template.Content = ""; // else saving throws with a dirty internal error - ServiceContext.FileService.SaveTemplate(template); - return template; - } - - [TestCase("/blah")] - [TestCase("/default.aspx/blah")] //this one is actually rather important since this is the path that comes through when we are running in pre-IIS 7 for the root document '/' ! - [TestCase("/home/Sub1/blah")] - [TestCase("/Home/Sub1/Blah")] //different cases - [TestCase("/home/Sub1.aspx/blah")] - public async Task Match_Document_By_Url_With_Template(string urlAsString) - { - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; - - var template1 = CreateTemplate("test"); - var template2 = CreateTemplate("blah"); - var umbracoContext = GetUmbracoContext(urlAsString, template1.Id, globalSettings: globalSettings); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext)); - var reqBuilder = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); - var webRoutingSettings = new WebRoutingSettings(); - var lookup = new ContentFinderByUrlAndTemplate( - LoggerFactory.CreateLogger(), - ServiceContext.FileService, - ServiceContext.ContentTypeService, - GetUmbracoContextAccessor(umbracoContext), - Microsoft.Extensions.Options.Options.Create(webRoutingSettings)); - - var result = lookup.TryFindContent(reqBuilder); - - IPublishedRequest frequest = reqBuilder.Build(); - - Assert.IsTrue(result); - Assert.IsNotNull(frequest.PublishedContent); - var templateAlias = frequest.GetTemplateAlias(); - Assert.IsNotNull(templateAlias ); - Assert.AreEqual("blah".ToUpperInvariant(), templateAlias.ToUpperInvariant()); - } - } -} diff --git a/tests/Umbraco.Tests/Routing/ContentFinderByUrlTests.cs b/tests/Umbraco.Tests/Routing/ContentFinderByUrlTests.cs deleted file mode 100644 index 35f06627fede..000000000000 --- a/tests/Umbraco.Tests/Routing/ContentFinderByUrlTests.cs +++ /dev/null @@ -1,156 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using NUnit.Framework; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests.Routing -{ - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class ContentFinderByUrlTests : BaseWebTest - { - [TestCase("/", 1046)] - [TestCase("/default.aspx", 1046)] //this one is actually rather important since this is the path that comes through when we are running in pre-IIS 7 for the root document '/' ! - [TestCase("/Sub1", 1173)] - [TestCase("/sub1", 1173)] - [TestCase("/sub1.aspx", 1173)] - [TestCase("/home/sub1", -1)] // should fail - - // these two are special. getNiceUrl(1046) returns "/" but getNiceUrl(1172) cannot also return "/" so - // we've made it return "/test-page" => we have to support that URL back in the lookup... - [TestCase("/home", 1046)] - [TestCase("/test-page", 1172)] - public async Task Match_Document_By_Url_Hide_Top_Level(string urlString, int expectedId) - { - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = true }; - - var snapshotService = CreatePublishedSnapshotService(globalSettings); - var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettings, snapshotService: snapshotService); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext)); - var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); - var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger(), GetUmbracoContextAccessor(umbracoContext)); - - Assert.IsTrue(globalSettings.HideTopLevelNodeFromPath); - - // FIXME: debugging - going further down, the routes cache is NOT empty?! - if (urlString == "/home/sub1") - System.Diagnostics.Debugger.Break(); - - var result = lookup.TryFindContent(frequest); - - if (expectedId > 0) - { - Assert.IsTrue(result); - Assert.AreEqual(expectedId, frequest.PublishedContent.Id); - } - else - { - Assert.IsFalse(result); - } - } - - [TestCase("/", 1046)] - [TestCase("/default.aspx", 1046)] //this one is actually rather important since this is the path that comes through when we are running in pre-IIS 7 for the root document '/' ! - [TestCase("/home", 1046)] - [TestCase("/home/Sub1", 1173)] - [TestCase("/Home/Sub1", 1173)] //different cases - [TestCase("/home/Sub1.aspx", 1173)] - public async Task Match_Document_By_Url(string urlString, int expectedId) - { - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; - - var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettings); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext)); - var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); - var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger(), GetUmbracoContextAccessor(umbracoContext)); - - Assert.IsFalse(globalSettings.HideTopLevelNodeFromPath); - - var result = lookup.TryFindContent(frequest); - - Assert.IsTrue(result); - Assert.AreEqual(expectedId, frequest.PublishedContent.Id); - } - /// - /// This test handles requests with special characters in the URL. - /// - /// - /// - [TestCase("/", 1046)] - [TestCase("/home/sub1/custom-sub-3-with-accént-character", 1179)] - [TestCase("/home/sub1/custom-sub-4-with-æøå", 1180)] - public async Task Match_Document_By_Url_With_Special_Characters(string urlString, int expectedId) - { - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; - - var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettings); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext)); - var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); - var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger(), GetUmbracoContextAccessor(umbracoContext)); - - var result = lookup.TryFindContent(frequest); - - Assert.IsTrue(result); - Assert.AreEqual(expectedId, frequest.PublishedContent.Id); - } - - /// - /// This test handles requests with a hostname associated. - /// The logic for handling this goes through the DomainHelper and is a bit different - /// from what happens in a normal request - so it has a separate test with a mocked - /// hostname added. - /// - /// - /// - [TestCase("/", 1046)] - [TestCase("/home/sub1/custom-sub-3-with-accént-character", 1179)] - [TestCase("/home/sub1/custom-sub-4-with-æøå", 1180)] - public async Task Match_Document_By_Url_With_Special_Characters_Using_Hostname(string urlString, int expectedId) - { - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; - - var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettings); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext)); - var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); - frequest.SetDomain(new DomainAndUri(new Domain(1, "mysite", -1, "en-US", false), new Uri("http://mysite/"))); - var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger(), GetUmbracoContextAccessor(umbracoContext)); - - var result = lookup.TryFindContent(frequest); - - Assert.IsTrue(result); - Assert.AreEqual(expectedId, frequest.PublishedContent.Id); - } - - /// - /// This test handles requests with a hostname with special characters associated. - /// The logic for handling this goes through the DomainHelper and is a bit different - /// from what happens in a normal request - so it has a separate test with a mocked - /// hostname added. - /// - /// - /// - [TestCase("/æøå/", 1046)] - [TestCase("/æøå/home/sub1", 1173)] - [TestCase("/æøå/home/sub1/custom-sub-3-with-accént-character", 1179)] - [TestCase("/æøå/home/sub1/custom-sub-4-with-æøå", 1180)] - public async Task Match_Document_By_Url_With_Special_Characters_In_Hostname(string urlString, int expectedId) - { - var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; - - var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettings); - var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext)); - var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); - frequest.SetDomain(new DomainAndUri(new Domain(1, "mysite/æøå", -1, "en-US", false), new Uri("http://mysite/æøå"))); - var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger(), GetUmbracoContextAccessor(umbracoContext)); - - var result = lookup.TryFindContent(frequest); - - Assert.IsTrue(result); - Assert.AreEqual(expectedId, frequest.PublishedContent.Id); - } - } -} diff --git a/tests/Umbraco.Tests/Routing/GetContentUrlsTests.cs b/tests/Umbraco.Tests/Routing/GetContentUrlsTests.cs deleted file mode 100644 index fe371e730237..000000000000 --- a/tests/Umbraco.Tests/Routing/GetContentUrlsTests.cs +++ /dev/null @@ -1,182 +0,0 @@ -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Services; -using Umbraco.Extensions; -using Umbraco.Tests.TestHelpers.Entities; - -namespace Umbraco.Tests.Routing -{ - [TestFixture] - public class GetContentUrlsTests : UrlRoutingTestBase - { - private GlobalSettings _globalSettings; - private WebRoutingSettings _webRoutingSettings; - private RequestHandlerSettings _requestHandlerSettings; - - public override void SetUp() - { - base.SetUp(); - - _globalSettings = new GlobalSettings(); - _webRoutingSettings = new WebRoutingSettings(); - _requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - } - - private ILocalizedTextService GetTextService() - { - var textService = Mock.Of( - x => x.Localize("content/itemNotPublished", - It.IsAny(), - It.IsAny>()) == "content/itemNotPublished"); - return textService; - } - - private ILocalizationService GetLangService(params string[] isoCodes) - { - var allLangs = isoCodes - .Select(CultureInfo.GetCultureInfo) - .Select(culture => new Language(_globalSettings, culture.Name) - { - CultureName = culture.DisplayName, - IsDefault = true, - IsMandatory = true - }).ToArray(); - - var langService = Mock.Of(x => x.GetAllLanguages() == allLangs); - return langService; - } - - [Test] - public async Task Content_Not_Published() - { - var contentType = MockedContentTypes.CreateBasicContentType(); - var content = MockedContent.CreateBasicContent(contentType); - content.Id = 1046; // FIXME: we are using this ID only because it's built into the test XML published cache - content.Path = "-1,1046"; - - var umbContext = GetUmbracoContext("http://localhost:8000"); - var publishedRouter = CreatePublishedRouter( - GetUmbracoContextAccessor(umbContext), - Factory, - contentFinders: new ContentFinderCollection(new[] { new ContentFinderByUrl(LoggerFactory.CreateLogger(), GetUmbracoContextAccessor(umbContext)) })); - var urls = (await content.GetContentUrlsAsync(publishedRouter, - umbContext, - GetLangService("en-US", "fr-FR"), GetTextService(), ServiceContext.ContentService, - VariationContextAccessor, - LoggerFactory.CreateLogger(), - UriUtility, - PublishedUrlProvider)).ToList(); - - Assert.AreEqual(1, urls.Count); - Assert.AreEqual("content/itemNotPublished", urls[0].Text); - Assert.IsFalse(urls[0].IsUrl); - } - - [Test] - public async Task Invariant_Root_Content_Published_No_Domains() - { - var contentType = MockedContentTypes.CreateBasicContentType(); - var content = MockedContent.CreateBasicContent(contentType); - content.Id = 1046; // FIXME: we are using this ID only because it's built into the test XML published cache - content.Path = "-1,1046"; - content.Published = true; - - var umbContext = GetUmbracoContext("http://localhost:8000"); - var umbracoContextAccessor = GetUmbracoContextAccessor(umbContext); - var urlProvider = new DefaultUrlProvider( - Microsoft.Extensions.Options.Options.Create(_requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), - umbracoContextAccessor, UriUtility); - var publishedUrlProvider = new UrlProvider( - umbracoContextAccessor, - Microsoft.Extensions.Options.Options.Create(_webRoutingSettings), - new UrlProviderCollection(new []{urlProvider}), - new MediaUrlProviderCollection(Enumerable.Empty()), - Mock.Of() - ); - - var publishedRouter = CreatePublishedRouter( - umbracoContextAccessor, - Factory, - contentFinders:new ContentFinderCollection(new[]{new ContentFinderByUrl(LoggerFactory.CreateLogger(), umbracoContextAccessor) })); - var urls = (await content.GetContentUrlsAsync(publishedRouter, - umbContext, - GetLangService("en-US", "fr-FR"), GetTextService(), ServiceContext.ContentService, - VariationContextAccessor, - LoggerFactory.CreateLogger(), - UriUtility, - publishedUrlProvider)).ToList(); - - Assert.AreEqual(1, urls.Count); - Assert.AreEqual("/home/", urls[0].Text); - Assert.AreEqual("en-US", urls[0].Culture); - Assert.IsTrue(urls[0].IsUrl); - } - - [Test] - public async Task Invariant_Child_Content_Published_No_Domains() - { - var contentType = MockedContentTypes.CreateBasicContentType(); - var parent = MockedContent.CreateBasicContent(contentType); - parent.Id = 1046; // FIXME: we are using this ID only because it's built into the test XML published cache - parent.Name = "home"; - parent.Path = "-1,1046"; - parent.Published = true; - var child = MockedContent.CreateBasicContent(contentType); - child.Name = "sub1"; - child.Id = 1173; // FIXME: we are using this ID only because it's built into the test XML published cache - child.Path = "-1,1046,1173"; - child.Published = true; - - var umbContext = GetUmbracoContext("http://localhost:8000"); - var umbracoContextAccessor = GetUmbracoContextAccessor(umbContext); - var urlProvider = new DefaultUrlProvider( - Microsoft.Extensions.Options.Options.Create(_requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - var publishedUrlProvider = new UrlProvider( - umbracoContextAccessor, - Microsoft.Extensions.Options.Options.Create(_webRoutingSettings), - new UrlProviderCollection(new []{urlProvider}), - new MediaUrlProviderCollection(Enumerable.Empty()), - Mock.Of() - ); - - var publishedRouter = CreatePublishedRouter( - umbracoContextAccessor, - Factory, - contentFinders: new ContentFinderCollection(new[] { new ContentFinderByUrl(LoggerFactory.CreateLogger(), umbracoContextAccessor) })); - var urls = (await child.GetContentUrlsAsync(publishedRouter, - umbContext, - GetLangService("en-US", "fr-FR"), GetTextService(), ServiceContext.ContentService, - VariationContextAccessor, - LoggerFactory.CreateLogger(), - UriUtility, - publishedUrlProvider - )).ToList(); - - Assert.AreEqual(1, urls.Count); - Assert.AreEqual("/home/sub1/", urls[0].Text); - Assert.AreEqual("en-US", urls[0].Culture); - Assert.IsTrue(urls[0].IsUrl); - } - - // TODO: We need a lot of tests here, the above was just to get started with being able to unit test this method - // * variant URLs without domains assigned, what happens? - // * variant URLs with domains assigned, but also having more languages installed than there are domains/cultures assigned - // * variant URLs with an ancestor culture unpublished - // * invariant URLs with ancestors as variants - // * ... probably a lot more - - } -} diff --git a/tests/Umbraco.Tests/Routing/RouteTestExtensions.cs b/tests/Umbraco.Tests/Routing/RouteTestExtensions.cs deleted file mode 100644 index 642488c25627..000000000000 --- a/tests/Umbraco.Tests/Routing/RouteTestExtensions.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.Web; -using System.Web.Routing; -using Moq; -using Umbraco.Tests.TestHelpers; - -namespace Umbraco.Tests.Routing -{ - public static class RouteTestExtensions - { - - /// - /// Return the route data for the URL based on a mocked context - /// - /// - /// - /// - public static RouteData GetDataForRoute(this RouteCollection routes, string requestUrl) - { - var context = new FakeHttpContextFactory(requestUrl); - return routes.GetDataForRoute(context.HttpContext); - } - - /// - /// Get the route data based on the URL and HTTP context - /// - /// - /// - /// - public static RouteData GetDataForRoute(this RouteCollection routes, HttpContextBase httpContext) - { - var data = routes.GetRouteData(httpContext); - - //set the route data on the request context - var requestMock = Mock.Get(httpContext.Request.RequestContext); - requestMock.Setup(x => x.RouteData).Returns(data); - - return data; - } - - /// - /// Checks if the URL will be ignored in the RouteTable - /// - /// - /// - /// - /// MVCContrib has a similar one but is faulty: - /// http://mvccontrib.codeplex.com/workitem/7173 - /// - public static bool ShouldIgnoreRoute(this string url) - { - var http = new FakeHttpContextFactory(url); - var r = RouteTable.Routes.GetRouteData(http.HttpContext); - if (r == null) return false; - return (r.RouteHandler is StopRoutingHandler); - } - - } -} diff --git a/tests/Umbraco.Tests/Routing/RoutesCacheTests.cs b/tests/Umbraco.Tests/Routing/RoutesCacheTests.cs deleted file mode 100644 index ba851bf76127..000000000000 --- a/tests/Umbraco.Tests/Routing/RoutesCacheTests.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using NUnit.Framework; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; - -namespace Umbraco.Tests.Routing -{ - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class RoutesCacheTests : BaseWebTest - { - [Test] - public void U4_7939() - { - //var routingContext = GetRoutingContext("/test", 1111); - var umbracoContext = GetUmbracoContext("/test", 0); - var cache = umbracoContext.PublishedSnapshot.Content as PublishedContentCache; - if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); - - // FIXME: not sure? - //PublishedContentCache.UnitTesting = false; // else does not write to routes cache - //Assert.IsFalse(PublishedContentCache.UnitTesting); - - var z = cache.GetByRoute(false, "/home/sub1"); - Assert.IsNotNull(z); - Assert.AreEqual(1173, z.Id); - - var routes = cache.RoutesCache.GetCachedRoutes(); - Assert.AreEqual(1, routes.Count); - - // before the fix, the following assert would fail because the route would - // have been stored as { 0, "/home/sub1" } - essentially meaning we were NOT - // storing anything in the route cache! - - Assert.AreEqual(1173, routes.Keys.First()); - Assert.AreEqual("/home/sub1", routes.Values.First()); - } - } -} diff --git a/tests/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs b/tests/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs deleted file mode 100644 index 3a2ccc23dfdf..000000000000 --- a/tests/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Microsoft.Extensions.Logging; -using NUnit.Framework; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Tests.Common; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Extensions; -using Umbraco.Tests.Testing; - -namespace Umbraco.Tests.Routing -{ - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class UrlProviderWithHideTopLevelNodeFromPathTests : BaseUrlProviderTest - { - private GlobalSettings _globalSettings; - - public override void SetUp() - { - _globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = HideTopLevelNodeFromPath }; - base.SetUp(); - PublishedSnapshotService = CreatePublishedSnapshotService(_globalSettings); - - - } - - protected override bool HideTopLevelNodeFromPath => true; - - protected override void ComposeSettings() - { - base.ComposeSettings(); - Builder.Services.AddUnique(x => Microsoft.Extensions.Options.Options.Create(_globalSettings)); - } - - [TestCase(1046, "/")] - [TestCase(1173, "/sub1/")] - [TestCase(1174, "/sub1/sub2/")] - [TestCase(1176, "/sub1/sub-3/")] - [TestCase(1177, "/sub1/custom-sub-1/")] - [TestCase(1178, "/sub1/custom-sub-2/")] - [TestCase(1175, "/sub-2/")] - [TestCase(1172, "/test-page/")] // not hidden because not first root - public void Get_Url_Hiding_Top_Level(int nodeId, string niceUrlMatch) - { - var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: _globalSettings, snapshotService:PublishedSnapshotService); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider( - Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); - - var result = publishedUrlProvider.GetUrl(nodeId); - Assert.AreEqual(niceUrlMatch, result); - } - } -} diff --git a/tests/Umbraco.Tests/Routing/UrlProviderWithoutHideTopLevelNodeFromPathTests.cs b/tests/Umbraco.Tests/Routing/UrlProviderWithoutHideTopLevelNodeFromPathTests.cs deleted file mode 100644 index bbadf897d073..000000000000 --- a/tests/Umbraco.Tests/Routing/UrlProviderWithoutHideTopLevelNodeFromPathTests.cs +++ /dev/null @@ -1,311 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Tests.Common; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.PublishedContent; - -namespace Umbraco.Tests.Routing -{ - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class UrlProviderWithoutHideTopLevelNodeFromPathTests : BaseUrlProviderTest - { - private readonly GlobalSettings _globalSettings; - - public UrlProviderWithoutHideTopLevelNodeFromPathTests() - { - _globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = HideTopLevelNodeFromPath }; - } - - protected override bool HideTopLevelNodeFromPath => false; - - protected override void ComposeSettings() - { - base.ComposeSettings(); - Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(_globalSettings)); - } - - /// - /// This checks that when we retrieve a NiceUrl for multiple items that there are no issues with cache overlap - /// and that they are all cached correctly. - /// - [Test] - public void Ensure_Cache_Is_Correct() - { - var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = false }; - - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: _globalSettings); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider( - Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); - - var samples = new Dictionary { - { 1046, "/home" }, - { 1173, "/home/sub1" }, - { 1174, "/home/sub1/sub2" }, - { 1176, "/home/sub1/sub-3" }, - { 1177, "/home/sub1/custom-sub-1" }, - { 1178, "/home/sub1/custom-sub-2" }, - { 1175, "/home/sub-2" }, - { 1172, "/test-page" } - }; - - foreach (var sample in samples) - { - var result = publishedUrlProvider.GetUrl(sample.Key); - Assert.AreEqual(sample.Value, result); - } - - var randomSample = new KeyValuePair(1177, "/home/sub1/custom-sub-1"); - for (int i = 0; i < 5; i++) - { - var result = publishedUrlProvider.GetUrl(randomSample.Key); - Assert.AreEqual(randomSample.Value, result); - } - - var cache = umbracoContext.Content as PublishedContentCache; - if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); - var cachedRoutes = cache.RoutesCache.GetCachedRoutes(); - Assert.AreEqual(8, cachedRoutes.Count); - - foreach (var sample in samples) - { - Assert.IsTrue(cachedRoutes.ContainsKey(sample.Key)); - Assert.AreEqual(sample.Value, cachedRoutes[sample.Key]); - } - - var cachedIds = cache.RoutesCache.GetCachedIds(); - Assert.AreEqual(0, cachedIds.Count); - } - - [TestCase(1046, "/home/")] - [TestCase(1173, "/home/sub1/")] - [TestCase(1174, "/home/sub1/sub2/")] - [TestCase(1176, "/home/sub1/sub-3/")] - [TestCase(1177, "/home/sub1/custom-sub-1/")] - [TestCase(1178, "/home/sub1/custom-sub-2/")] - [TestCase(1175, "/home/sub-2/")] - [TestCase(1172, "/test-page/")] - public void Get_Url_Not_Hiding_Top_Level(int nodeId, string niceUrlMatch) - { - var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: _globalSettings); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider( - Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); - - var result = publishedUrlProvider.GetUrl(nodeId); - Assert.AreEqual(niceUrlMatch, result); - } - - [Test] - public void Get_Url_For_Culture_Variant_Without_Domains_Non_Current_Url() - { - const string currentUri = "http://example.us/test"; - - var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - - var contentType = new PublishedContentType(Guid.NewGuid(), 666, "alias", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Culture); - var publishedContent = new SolidPublishedContent(contentType) { Id = 1234 }; - - var publishedContentCache = new Mock(); - publishedContentCache.Setup(x => x.GetRouteById(1234, "fr-FR")) - .Returns("9876/home/test-fr"); //prefix with the root id node with the domain assigned as per the umbraco standard - publishedContentCache.Setup(x => x.GetById(It.IsAny())) - .Returns(id => id == 1234 ? publishedContent : null); - - var domainCache = new Mock(); - domainCache.Setup(x => x.GetAssigned(It.IsAny(), false)) - .Returns((int contentId, bool includeWildcards) => Enumerable.Empty()); - - var snapshot = Mock.Of(x => x.Content == publishedContentCache.Object && x.Domains == domainCache.Object); - - var snapshotService = new Mock(); - snapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())) - .Returns(snapshot); - - var umbracoContext = GetUmbracoContext(currentUri, - globalSettings: _globalSettings, - snapshotService: snapshotService.Object); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider( - Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); - - //even though we are asking for a specific culture URL, there are no domains assigned so all that can be returned is a normal relative URL. - var url = publishedUrlProvider.GetUrl(1234, culture: "fr-FR"); - - Assert.AreEqual("/home/test-fr/", url); - } - - /// - /// This tests DefaultUrlProvider.GetUrl with a specific culture when the current URL is the culture specific domain - /// - [Test] - public void Get_Url_For_Culture_Variant_With_Current_Url() - { - const string currentUri = "http://example.fr/test"; - - var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - - var contentType = new PublishedContentType(Guid.NewGuid(), 666, "alias", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Culture); - var publishedContent = new SolidPublishedContent(contentType) { Id = 1234 }; - - var publishedContentCache = new Mock(); - publishedContentCache.Setup(x => x.GetRouteById(1234, "fr-FR")) - .Returns("9876/home/test-fr"); //prefix with the root id node with the domain assigned as per the umbraco standard - publishedContentCache.Setup(x => x.GetById(It.IsAny())) - .Returns(id => id == 1234 ? publishedContent : null); - - var domainCache = new Mock(); - domainCache.Setup(x => x.GetAssigned(It.IsAny(), false)) - .Returns((int contentId, bool includeWildcards) => - { - if (contentId != 9876) return Enumerable.Empty(); - return new[] - { - new Domain(2, "example.us", 9876, "en-US", false), //default - new Domain(3, "example.fr", 9876, "fr-FR", false) - }; - }); - domainCache.Setup(x => x.DefaultCulture).Returns(CultureInfo.GetCultureInfo("en-US").Name); - - var snapshot = Mock.Of(x => x.Content == publishedContentCache.Object && x.Domains == domainCache.Object); - - var snapshotService = new Mock(); - snapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())) - .Returns(snapshot); - - var umbracoContext = GetUmbracoContext(currentUri, - globalSettings: _globalSettings, - snapshotService: snapshotService.Object); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider( - Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); - - var url = publishedUrlProvider.GetUrl(1234, culture: "fr-FR"); - - Assert.AreEqual("/home/test-fr/", url); - } - - /// - /// This tests DefaultUrlProvider.GetUrl with a specific culture when the current URL is not the culture specific domain - /// - [Test] - public void Get_Url_For_Culture_Variant_Non_Current_Url() - { - const string currentUri = "http://example.us/test"; - - var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - - var contentType = new PublishedContentType(Guid.NewGuid(), 666, "alias", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Culture); - var publishedContent = new SolidPublishedContent(contentType) { Id = 1234 }; - - var publishedContentCache = new Mock(); - publishedContentCache.Setup(x => x.GetRouteById(1234, "fr-FR")) - .Returns("9876/home/test-fr"); //prefix with the root id node with the domain assigned as per the umbraco standard - publishedContentCache.Setup(x => x.GetById(It.IsAny())) - .Returns(id => id == 1234 ? publishedContent : null); - - var domainCache = new Mock(); - domainCache.Setup(x => x.GetAssigned(It.IsAny(), false)) - .Returns((int contentId, bool includeWildcards) => - { - if (contentId != 9876) return Enumerable.Empty(); - return new[] - { - new Domain(2, "example.us", 9876, "en-US", false), //default - new Domain(3, "example.fr", 9876, "fr-FR", false) - }; - }); - domainCache.Setup(x => x.DefaultCulture).Returns(CultureInfo.GetCultureInfo("en-US").Name); - - var snapshot = Mock.Of(x => x.Content == publishedContentCache.Object && x.Domains == domainCache.Object); - - var snapshotService = new Mock(); - snapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())) - .Returns(snapshot); - - var umbracoContext = GetUmbracoContext(currentUri, - globalSettings: _globalSettings, - snapshotService: snapshotService.Object); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider( - Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - - - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); - var url = publishedUrlProvider.GetUrl(1234, culture: "fr-FR"); - - //the current uri is not the culture specific domain we want, so the result is an absolute path to the culture specific domain - Assert.AreEqual("http://example.fr/home/test-fr/", url); - } - - [Test] - public void Get_Url_Relative_Or_Absolute() - { - var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; - - var umbracoContext = GetUmbracoContext("http://example.com/test", 1111, globalSettings: _globalSettings); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider( - Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), umbracoContextAccessor, UriUtility); - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); - - Assert.AreEqual("/home/sub1/custom-sub-1/", publishedUrlProvider.GetUrl(1177)); - - publishedUrlProvider.Mode = UrlMode.Absolute; - Assert.AreEqual("http://example.com/home/sub1/custom-sub-1/", publishedUrlProvider.GetUrl(1177)); - } - - [Test] - public void Get_Url_Unpublished() - { - var requestHandlerSettings = new RequestHandlerSettings(); - - var urlProvider = new DefaultUrlProvider(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), - LoggerFactory.CreateLogger(), - new SiteDomainMapper(), UmbracoContextAccessor, UriUtility); - var umbracoContext = GetUmbracoContext("http://example.com/test", 1111, globalSettings: _globalSettings); - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); - - //mock the Umbraco settings that we need - - Assert.AreEqual("#", publishedUrlProvider.GetUrl(999999)); - - publishedUrlProvider.Mode = UrlMode.Absolute; - - Assert.AreEqual("#", publishedUrlProvider.GetUrl(999999)); - } - } -} diff --git a/tests/Umbraco.Tests/Routing/UrlRoutingTestBase.cs b/tests/Umbraco.Tests/Routing/UrlRoutingTestBase.cs deleted file mode 100644 index e2f195b09d46..000000000000 --- a/tests/Umbraco.Tests/Routing/UrlRoutingTestBase.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Extensions; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; - -namespace Umbraco.Tests.Routing -{ - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public abstract class UrlRoutingTestBase : BaseWebTest - { - /// - /// Sets up the mock domain service - /// - /// - protected IDomainService SetupDomainServiceMock(IEnumerable allDomains) - { - var domainService = Mock.Get(ServiceContext.DomainService); - //setup mock domain service - domainService.Setup(service => service.GetAll(It.IsAny())) - .Returns((bool incWildcards) => incWildcards ? allDomains : allDomains.Where(d => d.IsWildcard == false)); - domainService.Setup(service => service.GetAssignedDomains(It.IsAny(), It.IsAny())) - .Returns((int id, bool incWildcards) => allDomains.Where(d => d.RootContentId == id && (incWildcards || d.IsWildcard == false))); - return domainService.Object; - } - - protected override void Compose() - { - base.Compose(); - - Builder.Services.AddUnique(GetServiceContext()); - } - - protected ServiceContext GetServiceContext() - { - // get the mocked service context to get the mocked domain service - var serviceContext = TestObjects.GetServiceContextMock(Factory); - - //setup mock domain service - var domainService = Mock.Get(serviceContext.DomainService); - domainService.Setup(service => service.GetAll(It.IsAny())) - .Returns((bool incWildcards) => new[] - { - new UmbracoDomain("domain1.com/"){Id = 1, LanguageId = LangDeId, RootContentId = 1001, LanguageIsoCode = "de-DE"}, - new UmbracoDomain("domain1.com/en"){Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}, - new UmbracoDomain("domain1.com/fr"){Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"} - }); - - return serviceContext; - } - - public const int LangDeId = 333; - public const int LangEngId = 334; - public const int LangFrId = 335; - public const int LangCzId = 336; - public const int LangNlId = 337; - public const int LangDkId = 338; - } -} diff --git a/tests/Umbraco.Tests/Scoping/PassThroughEventDispatcherTests.cs b/tests/Umbraco.Tests/Scoping/PassThroughEventDispatcherTests.cs deleted file mode 100644 index ca4767c0f114..000000000000 --- a/tests/Umbraco.Tests/Scoping/PassThroughEventDispatcherTests.cs +++ /dev/null @@ -1,59 +0,0 @@ -using NUnit.Framework; - -namespace Umbraco.Tests.Scoping -{ - [TestFixture] - [NUnit.Framework.Ignore("Cannot dispatch events on NoScope!")] - public class PassThroughEventDispatcherTests - { - // FIXME: so... should we remove, or enable, these tests? - - // [Test] - // public void TriggersCancelableEvents() - // { - // var counter = 0; - - // DoThing1 += (sender, args) => { counter++; }; - - // var scopeProvider = new ScopeProvider(Mock.Of()); - // var events = scopeProvider.GetAmbientOrNoScope().Events; - // events.DispatchCancelable(DoThing1, this, new CancellableEventArgs()); - - // Assert.AreEqual(1, counter); - // } - - // [Test] - // public void TriggersEvents() - // { - // var counter = 0; - - // DoThing1 += (sender, args) => { counter++; }; - // DoThing2 += (sender, args) => { counter++; }; - // DoThing3 += (sender, args) => { counter++; }; - - // var scopeProvider = new ScopeProvider(Mock.Of()); - // var events = scopeProvider.GetAmbientOrNoScope().Events; - // events.Dispatch(DoThing1, this, new EventArgs()); - // events.Dispatch(DoThing2, this, new EventArgs()); - // events.Dispatch(DoThing3, this, new EventArgs()); - - // Assert.AreEqual(3, counter); - // } - - // [Test] - // public void DoesNotQueueEvents() - // { - // var scopeProvider = new ScopeProvider(Mock.Of()); - // var events = scopeProvider.GetAmbientOrNoScope().Events; - // events.Dispatch(DoThing1, this, new EventArgs()); - // events.Dispatch(DoThing2, this, new EventArgs()); - // events.Dispatch(DoThing3, this, new EventArgs()); - - // Assert.IsEmpty(events.GetEvents(EventDefinitionFilter.All)); - // } - - // public event EventHandler DoThing1; - // public event EventHandler DoThing2; - // public event TypedEventHandler DoThing3; - } -} diff --git a/tests/Umbraco.Tests/Scoping/ScopedXmlTests.cs b/tests/Umbraco.Tests/Scoping/ScopedXmlTests.cs deleted file mode 100644 index 53ef2e0246a7..000000000000 --- a/tests/Umbraco.Tests/Scoping/ScopedXmlTests.cs +++ /dev/null @@ -1,303 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Xml; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Notifications; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Sync; -using Umbraco.Cms.Infrastructure.Sync; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Extensions; -using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.TestHelpers; -using Umbraco.Web.Composing; - -namespace Umbraco.Tests.Scoping -{ - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] - public class ScopedXmlTests : TestWithDatabaseBase - { - private DistributedCacheBinder _distributedCacheBinder; - - protected override void Compose() - { - base.Compose(); - - // the cache refresher component needs to trigger to refresh caches - // but then, it requires a lot of plumbing ;( - // FIXME: and we cannot inject a DistributedCache yet - // so doing all this mess - Builder.Services.AddUnique(); - Builder.Services.AddUnique(f => Mock.Of()); - Builder.WithCollectionBuilder() - .Add(() => Builder.TypeLoader.GetCacheRefreshers()); - Builder.AddNotificationHandler(); - } - - protected override void ComposeSettings() - { - var contentSettings = new ContentSettings(); - var globalSettings = new GlobalSettings(); - var userPasswordConfigurationSettings = new UserPasswordConfigurationSettings(); - - Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(contentSettings)); - Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(globalSettings)); - Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(userPasswordConfigurationSettings)); - } - - - public class NotificationHandler : INotificationHandler - { - public void Handle(ContentPublishedNotification notification) => PublishedContent?.Invoke(notification); - - public static Action PublishedContent { get; set; } - } - - [TearDown] - public void Teardown() - { - NotificationHandler.PublishedContent = null; - SafeXmlReaderWriter.Cloning = null; - } - - // in 7.6, content.Instance - // .XmlContent - comes from .XmlContentInternal and is cached in context items for current request - // .XmlContentInternal - the actual main xml document - // become in 8 - // xmlStore.Xml - the actual main xml document - // publishedContentCache.GetXml() - the captured xml - - private static XmlStore XmlStore => (Current.Factory.GetRequiredService() as XmlPublishedSnapshotService).XmlStore; - private static XmlDocument XmlMaster => XmlStore.Xml; - private static XmlDocument XmlInContext => ((PublishedContentCache) Umbraco.Web.Composing.Current.UmbracoContext.Content).GetXml(false); - - [TestCase(true)] - [TestCase(false)] - public void TestScope(bool complete) - { - var umbracoContext = GetUmbracoContext("http://example.com/", setSingleton: true); - - // sanity checks - Assert.AreSame(umbracoContext, Umbraco.Web.Composing.Current.UmbracoContext); - Assert.AreSame(XmlStore, ((PublishedContentCache) umbracoContext.Content).XmlStore); - - // create document type, document - var contentType = new ContentType(ShortStringHelper, -1) { Alias = "CustomDocument", Name = "Custom Document" }; - ServiceContext.ContentTypeService.Save(contentType); - var item = new Content("name", -1, contentType); - - // wire cache refresher - _distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers)); - - // check xml in context = "before" - var xml = XmlInContext; - var beforeXml = xml; - var beforeOuterXml = beforeXml.OuterXml; - Console.WriteLine("Xml Before:"); - Console.WriteLine(xml.OuterXml); - - // event handler - var evented = 0; - NotificationHandler.PublishedContent = notification => - { - evented++; - - // should see the changes in context, not in master - xml = XmlInContext; - Assert.AreNotSame(beforeXml, xml); - Console.WriteLine("Xml Event:"); - Console.WriteLine(xml.OuterXml); - var node = xml.GetElementById(item.Id.ToString()); - Assert.IsNotNull(node); - - xml = XmlMaster; - Assert.AreSame(beforeXml, xml); - Assert.AreEqual(beforeOuterXml, xml.OuterXml); - }; - - using (var scope = ScopeProvider.CreateScope()) - { - ServiceContext.ContentService.SaveAndPublish(item); // should create an xml clone - item.Name = "changed"; - ServiceContext.ContentService.SaveAndPublish(item); // should re-use the xml clone - - // this should never change - Assert.AreEqual(beforeOuterXml, beforeXml.OuterXml); - - // this does not change, other thread don't see the changes - xml = XmlMaster; - Assert.AreSame(beforeXml, xml); - Console.WriteLine("XmlInternal During:"); - Console.WriteLine(xml.OuterXml); - Assert.AreEqual(beforeOuterXml, xml.OuterXml); - - // this does not change during the scope (only in events) - // because it is the events that trigger the changes - xml = XmlInContext; - Assert.IsNotNull(xml); - Assert.AreSame(beforeXml, xml); - Assert.AreEqual(beforeOuterXml, xml.OuterXml); - - // note - // this means that, as long as ppl don't create scopes, they'll see their - // changes right after SaveAndPublish, but if they create scopes, - // they will have to wail until the scope is completed, ie wait until the - // events trigger, to use eg GetUrl etc - - if (complete) - scope.Complete(); - } - - //The reason why there is only 1 event occuring is because we are publishing twice for the same event for the same - //object and the scope deduplicates the events(uses the latest) - Assert.AreEqual(complete? 1 : 0, evented); - - // this should never change - Assert.AreEqual(beforeOuterXml, beforeXml.OuterXml); - - xml = XmlInContext; - Console.WriteLine("Xml After:"); - Console.WriteLine(xml.OuterXml); - if (complete) - { - var node = xml.GetElementById(item.Id.ToString()); - Assert.IsNotNull(node); - } - else - { - Assert.AreSame(beforeXml, xml); - Assert.AreEqual(beforeOuterXml, xml.OuterXml); // nothing has changed! - } - - xml = XmlMaster; - if (complete) - { - var node = xml.GetElementById(item.Id.ToString()); - Assert.IsNotNull(node); - } - else - { - Assert.AreSame(beforeXml, xml); - Assert.AreEqual(beforeOuterXml, xml.OuterXml); // nothing has changed! - } - } - - [TestCase(true)] - [TestCase(false)] - public void TestScopeMany(bool complete) - { - var umbracoContext = GetUmbracoContext("http://example.com/", setSingleton: true); - - // sanity checks - Assert.AreSame(umbracoContext, Umbraco.Web.Composing.Current.UmbracoContext); - Assert.AreSame(XmlStore, ((PublishedContentCache)umbracoContext.Content).XmlStore); - - // create document type - var contentType = new ContentType(ShortStringHelper,-1) { Alias = "CustomDocument", Name = "Custom Document" }; - ServiceContext.ContentTypeService.Save(contentType); - - // wire cache refresher - _distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers)); - - // check xml in context = "before" - var xml = XmlInContext; - var beforeXml = xml; - var beforeOuterXml = beforeXml.OuterXml; - var item = new Content("name", -1, contentType); - const int count = 10; - var ids = new int[count]; - var clones = 0; - - SafeXmlReaderWriter.Cloning = () => { clones++; }; - - Console.WriteLine("Xml Before:"); - Console.WriteLine(xml.OuterXml); - - using (var scope = ScopeProvider.CreateScope()) - { - ServiceContext.ContentService.SaveAndPublish(item); - - for (var i = 0; i < count; i++) - { - var temp = new Content("content_" + i, -1, contentType); - ServiceContext.ContentService.SaveAndPublish(temp); - ids[i] = temp.Id; - } - - // this should never change - Assert.AreEqual(beforeOuterXml, beforeXml.OuterXml); - - xml = XmlMaster; - Assert.IsNotNull(xml); - Console.WriteLine("Xml InScope (before complete):"); - Console.WriteLine(xml.OuterXml); - Assert.AreEqual(beforeOuterXml, xml.OuterXml); - - if (complete) - scope.Complete(); - - xml = XmlMaster; - Assert.IsNotNull(xml); - Console.WriteLine("Xml InScope (after complete):"); - Console.WriteLine(xml.OuterXml); - Assert.AreEqual(beforeOuterXml, xml.OuterXml); - } - - var scopeProvider = ScopeProvider; - Assert.IsNotNull(scopeProvider); - // ambient scope may be null, or maybe not, depending on whether the code that - // was called did proper scoped work, or some direct (NoScope) use of the database - Assert.IsNull(scopeProvider.AmbientContext); - - // limited number of clones! - Assert.AreEqual(complete ? 1 : 0, clones); - - // this should never change - Assert.AreEqual(beforeOuterXml, beforeXml.OuterXml); - - xml = XmlMaster; - Assert.IsNotNull(xml); - Console.WriteLine("Xml After:"); - Console.WriteLine(xml.OuterXml); - if (complete) - { - var node = xml.GetElementById(item.Id.ToString()); - Assert.IsNotNull(node); - - for (var i = 0; i < 10; i++) - { - node = xml.GetElementById(ids[i].ToString()); - Assert.IsNotNull(node); - } - } - else - { - Assert.AreEqual(beforeOuterXml, xml.OuterXml); // nothing has changed! - } - } - - public class LocalServerMessenger : ServerMessengerBase - { - public LocalServerMessenger() - : base(false) - { } - - public override void SendMessages() { } - - public override void Sync() { } - - protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) - { - throw new NotImplementedException(); - } - } - } -} diff --git a/tests/Umbraco.Tests/Services/Importing/Dictionary-Package.xml b/tests/Umbraco.Tests/Services/Importing/Dictionary-Package.xml deleted file mode 100644 index 18ff588d6404..000000000000 --- a/tests/Umbraco.Tests/Services/Importing/Dictionary-Package.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - Dictionary-Package - 1.0 - MIT license - http://not.available - - 3 - 0 - 0 - - - - Test - http://not.available - - - - - - - - - - - - - - - - - - diff --git a/tests/Umbraco.Tests/Services/TestWithSomeContentBase.cs b/tests/Umbraco.Tests/Services/TestWithSomeContentBase.cs deleted file mode 100644 index 4b99f3d127d0..000000000000 --- a/tests/Umbraco.Tests/Services/TestWithSomeContentBase.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Threading; -using NUnit.Framework; -using Umbraco.Cms.Core.Models; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; - -namespace Umbraco.Tests.Services -{ - [TestFixture] - public abstract class TestWithSomeContentBase : TestWithDatabaseBase - { - public override void SetUp() - { - base.SetUp(); - CreateTestData(); - } - - public virtual void CreateTestData() - { - //NOTE Maybe not the best way to create/save test data as we are using the services, which are being tested. - - //Create and Save ContentType "umbTextpage" -> 1060 - ContentType contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage", "Textpage"); - contentType.Key = new Guid("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! - ServiceContext.ContentTypeService.Save(contentType); - - //Create and Save Content "Homepage" based on "umbTextpage" -> 1061 - Content textpage = MockedContent.CreateSimpleContent(contentType); - textpage.Key = new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0"); - ServiceContext.ContentService.Save(textpage, 0); - - //Create and Save Content "Text Page 1" based on "umbTextpage" -> 1062 - Content subpage = MockedContent.CreateSimpleContent(contentType, "Text Page 1", textpage.Id); - subpage.ContentSchedule.Add(DateTime.Now.AddMinutes(-5), null); - ServiceContext.ContentService.Save(subpage, 0); - - //Create and Save Content "Text Page 1" based on "umbTextpage" -> 1063 - Content subpage2 = MockedContent.CreateSimpleContent(contentType, "Text Page 2", textpage.Id); - ServiceContext.ContentService.Save(subpage2, 0); - - Content subpage3 = MockedContent.CreateSimpleContent(contentType, "Text Page 3", textpage.Id); - ServiceContext.ContentService.Save(subpage3, 0); - - //Create and Save Content "Text Page Deleted" based on "umbTextpage" -> 1064 - Content trashed = MockedContent.CreateSimpleContent(contentType, "Text Page Deleted", -20); - trashed.Trashed = true; - ServiceContext.ContentService.Save(trashed, 0); - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs b/tests/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs deleted file mode 100644 index d0717c1f78da..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.IO; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; -using Moq; -using NPoco; -using NUnit.Framework; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Infrastructure.Persistence.Mappers; -using Umbraco.Cms.Persistence.SqlCe; -using Umbraco.Extensions; -using Umbraco.Web; -using Umbraco.Web.Composing; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Tests.TestHelpers -{ - [TestFixture] - public abstract class BaseUsingSqlCeSyntax - { - protected IMapperCollection Mappers { get; private set; } - - protected ISqlContext SqlContext { get; private set; } - - internal TestObjects TestObjects = new TestObjects(); - - protected Sql Sql() - { - return NPoco.Sql.BuilderFor(SqlContext); - } - - [SetUp] - public virtual void Initialize() - { - var services = TestHelper.GetRegister(); - - var ioHelper = TestHelper.IOHelper; - var logger = new ProfilingLogger(Mock.Of>(), Mock.Of()); - var typeFinder = TestHelper.GetTypeFinder(); - var typeLoader = new TypeLoader(typeFinder, NoAppCache.Instance, - new DirectoryInfo(ioHelper.MapPath(Constants.SystemDirectories.TempData)), - Mock.Of>(), - logger, - false); - - var composition = new UmbracoBuilder(services, Mock.Of(), TestHelper.GetMockedTypeLoader()); - - - services.AddUnique(_ => Mock.Of()); - services.AddUnique(_ => NullLoggerFactory.Instance); - services.AddUnique(_ => Mock.Of()); - services.AddUnique(typeLoader); - - composition.WithCollectionBuilder() - .AddCoreMappers(); - - services.AddUnique(_ => SqlContext); - - var factory = Current.Factory = TestHelper.CreateServiceProvider(composition); - - var pocoMappers = new NPoco.MapperCollection { new PocoMapper() }; - var pocoDataFactory = new FluentPocoDataFactory((type, iPocoDataFactory) => new PocoDataBuilder(type, pocoMappers).Init()); - var sqlSyntax = new SqlCeSyntaxProvider(Options.Create(new GlobalSettings())); - SqlContext = new SqlContext(sqlSyntax, DatabaseType.SQLCe, pocoDataFactory, new Lazy(() => factory.GetRequiredService())); - Mappers = factory.GetRequiredService(); - - SetUp(); - } - - public virtual void SetUp() - {} - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/tests/Umbraco.Tests/TestHelpers/BaseWebTest.cs deleted file mode 100644 index d686856bb2a5..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.Linq; -using System.Threading; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure.Serialization; -using Umbraco.Cms.Tests.Common; -using Umbraco.Extensions; -using Umbraco.Tests.PublishedContent; -using Umbraco.Tests.TestHelpers.Stubs; -using Umbraco.Web.Composing; - -namespace Umbraco.Tests.TestHelpers -{ - [TestFixture] - public abstract class BaseWebTest : TestWithDatabaseBase - { - protected override void Compose() - { - base.Compose(); - - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - } - - protected override void Initialize() - { - base.Initialize(); - - // need to specify a custom callback for unit tests - // AutoPublishedContentTypes generates properties automatically - - var serializer = new ConfigurationEditorJsonSerializer(); - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(DataValueEditorFactory), serializer) { Id = 1 }); - - var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); - var type = new AutoPublishedContentType(Guid.NewGuid(), 0, "anything", new PublishedPropertyType[] { }); - ContentTypesCache.GetPublishedContentTypeByAlias = alias => GetPublishedContentTypeByAlias(alias) ?? type; - } - - protected virtual PublishedContentType GetPublishedContentTypeByAlias(string alias) => null; - - protected override string GetXmlContent(int templateId) - { - return @" - - - - -]> - - - - - 1 - - This is some content]]> - - - - - - - - - - - - - - - - - - -"; - } - - internal PublishedRouter CreatePublishedRouter(IUmbracoContextAccessor umbracoContextAccessor, IServiceProvider container = null, ContentFinderCollection contentFinders = null) - { - var webRoutingSettings = new WebRoutingSettings(); - return CreatePublishedRouter(umbracoContextAccessor, webRoutingSettings, container ?? Factory, contentFinders); - } - - internal static PublishedRouter CreatePublishedRouter(IUmbracoContextAccessor umbracoContextAccessor, WebRoutingSettings webRoutingSettings, IServiceProvider container = null, ContentFinderCollection contentFinders = null) - => new PublishedRouter( - Microsoft.Extensions.Options.Options.Create(webRoutingSettings), - contentFinders ?? new ContentFinderCollection(Enumerable.Empty()), - new TestLastChanceFinder(), - new TestVariationContextAccessor(), - new ProfilingLogger(Mock.Of>(), Mock.Of()), - Mock.Of>(), - Mock.Of(), - Mock.Of(), - container?.GetRequiredService() ?? Current.Factory.GetRequiredService(), - container?.GetRequiredService() ?? Current.Factory.GetRequiredService(), - container?.GetRequiredService() ?? Current.Factory.GetRequiredService(), - umbracoContextAccessor, - Mock.Of() - ); - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/ControllerTesting/AuthenticateEverythingExtensions.cs b/tests/Umbraco.Tests/TestHelpers/ControllerTesting/AuthenticateEverythingExtensions.cs deleted file mode 100644 index c812eeb41ded..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/ControllerTesting/AuthenticateEverythingExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using Microsoft.Owin.Extensions; -using Owin; - -namespace Umbraco.Tests.TestHelpers.ControllerTesting -{ - public static class AuthenticateEverythingExtensions - { - public static IAppBuilder AuthenticateEverything(this IAppBuilder app) - { - if (app == null) - throw new ArgumentNullException("app"); - app.Use(typeof(AuthenticateEverythingMiddleware), (object)app, (object)new AuthenticateEverythingMiddleware.AuthenticateEverythingAuthenticationOptions()); - app.UseStageMarker(PipelineStage.Authenticate); - return app; - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/ControllerTesting/AuthenticateEverythingMiddleware.cs b/tests/Umbraco.Tests/TestHelpers/ControllerTesting/AuthenticateEverythingMiddleware.cs deleted file mode 100644 index 96239d5921de..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/ControllerTesting/AuthenticateEverythingMiddleware.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Security.Claims; -using System.Threading.Tasks; -using Microsoft.Owin; -using Microsoft.Owin.Security; -using Microsoft.Owin.Security.Infrastructure; -using Owin; -using Umbraco.Extensions; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Security; - -namespace Umbraco.Tests.TestHelpers.ControllerTesting -{ - /// - /// Ensures there's an admin user assigned to the request - /// - public class AuthenticateEverythingMiddleware : AuthenticationMiddleware - { - public AuthenticateEverythingMiddleware(OwinMiddleware next, IAppBuilder app, AuthenticationOptions options) - : base(next, options) - { - } - - protected override AuthenticationHandler CreateHandler() - { - return new AuthenticateEverythingHandler(); - } - - public class AuthenticateEverythingHandler : AuthenticationHandler - { - protected override Task AuthenticateCoreAsync() - { - var securityStamp = Guid.NewGuid().ToString(); - - var identity = new ClaimsIdentity(); - identity.AddRequiredClaims( - Cms.Core.Constants.Security.SuperUserIdAsString, - "admin", - "Admin", - new[] { -1 }, - new[] { -1 }, - "en-US", - securityStamp, - new[] { "content", "media", "members" }, - new[] { "admin" }); - - return Task.FromResult(new AuthenticationTicket( - identity, - new AuthenticationProperties() - { - ExpiresUtc = DateTime.Now.AddDays(1) - })); - } - } - - public class AuthenticateEverythingAuthenticationOptions : AuthenticationOptions - { - public AuthenticateEverythingAuthenticationOptions() - : base("AuthenticateEverything") - { - AuthenticationMode = AuthenticationMode.Active; - } - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/ControllerTesting/SpecificAssemblyResolver.cs b/tests/Umbraco.Tests/TestHelpers/ControllerTesting/SpecificAssemblyResolver.cs deleted file mode 100644 index a31637981b1f..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/ControllerTesting/SpecificAssemblyResolver.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; -using System.Reflection; -using System.Web.Http.Dispatcher; - -namespace Umbraco.Tests.TestHelpers.ControllerTesting -{ - public class SpecificAssemblyResolver : IAssembliesResolver - { - private readonly Assembly[] _assemblies; - - public SpecificAssemblyResolver(Assembly[] assemblies) - { - _assemblies = assemblies; - } - - public ICollection GetAssemblies() - { - return _assemblies; - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivator.cs b/tests/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivator.cs deleted file mode 100644 index 1c1687dec8a7..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivator.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Net.Http; -using System.Web.Http; -using Umbraco.Cms.Core.Web; -using Umbraco.Web; - -namespace Umbraco.Tests.TestHelpers.ControllerTesting -{ - public class TestControllerActivator : TestControllerActivatorBase - { - private readonly Func _factory; - - public TestControllerActivator(Func factory) - { - _factory = factory; - } - - protected override ApiController CreateController(Type controllerType, HttpRequestMessage msg, IUmbracoContextAccessor umbracoContextAccessor) - { - return _factory(msg, umbracoContextAccessor); - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/tests/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs deleted file mode 100644 index 6e7da0a5581d..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs +++ /dev/null @@ -1,157 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Security.Claims; -using System.Web; -using System.Web.Http; -using System.Web.Http.Controllers; -using System.Web.Http.Dispatcher; -using Moq; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Models.Membership; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Tests.Common; -using Umbraco.Extensions; -using Umbraco.Tests.TestHelpers.Entities; -using Umbraco.Web; -using Umbraco.Web.WebApi; - -namespace Umbraco.Tests.TestHelpers.ControllerTesting -{ - /// - /// Used to mock all of the services required for re-mocking and testing controllers - /// - /// - /// A more complete version of this is found in the Umbraco REST API project but this has the basics covered - /// - public abstract class TestControllerActivatorBase : DefaultHttpControllerActivator, IHttpControllerActivator - { - IHttpController IHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) - { - // default - if (!typeof (UmbracoApiControllerBase).IsAssignableFrom(controllerType)) - return base.Create(request, controllerDescriptor, controllerType); - - var owinContext = request.TryGetOwinContext().Result; - - var mockedUserService = Mock.Of(); - var mockedContentService = Mock.Of(); - var mockedMediaService = Mock.Of(); - var mockedEntityService = Mock.Of(); - var mockedMemberService = Mock.Of(); - var mockedMemberTypeService = Mock.Of(); - var mockedDataTypeService = Mock.Of(); - var mockedContentTypeService = Mock.Of(); - - var serviceContext = ServiceContext.CreatePartial( - userService: mockedUserService, - contentService: mockedContentService, - mediaService: mockedMediaService, - entityService: mockedEntityService, - memberService: mockedMemberService, - memberTypeService: mockedMemberTypeService, - dataTypeService: mockedDataTypeService, - contentTypeService: mockedContentTypeService, - localizedTextService:Mock.Of()); - - var globalSettings = new GlobalSettings(); - - // FIXME: v8? - ////new app context - //var dbCtx = new Mock(Mock.Of(), Mock.Of(), Mock.Of(), "test"); - ////ensure these are set so that the appctx is 'Configured' - //dbCtx.Setup(x => x.CanConnect).Returns(true); - //dbCtx.Setup(x => x.IsDatabaseConfigured).Returns(true); - //var appCtx = ApplicationContext.EnsureContext( - // dbCtx.Object, - // //pass in mocked services - // serviceContext, - // CacheHelper.CreateDisabledCacheHelper(), - // new ProfilingLogger(Mock.Of(), Mock.Of()), - // true); - - var httpContextItems = new Dictionary - { - //add the special owin environment to the httpcontext items, this is how the GetOwinContext works - ["owin.Environment"] = new Dictionary() - }; - - //httpcontext with an auth'd user - var httpContext = Mock.Of( - http => http.User == owinContext.Authentication.User - //ensure the request exists with a cookies collection - && http.Request == Mock.Of(r => r.Cookies == new HttpCookieCollection() - && r.RequestContext == new System.Web.Routing.RequestContext - { - RouteData = new System.Web.Routing.RouteData() - }) - //ensure the request exists with an items collection - && http.Items == httpContextItems); - //chuck it into the props since this is what MS does when hosted and it's needed there - request.Properties["MS_HttpContext"] = httpContext; - - var backofficeIdentity = (ClaimsIdentity) owinContext.Authentication.User.Identity; - - var backofficeSecurity = new Mock(); - - //mock CurrentUser - var groups = new List(); - for (var index = 0; index < backofficeIdentity.GetRoles().Length; index++) - { - var role = backofficeIdentity.GetRoles()[index]; - groups.Add(new ReadOnlyUserGroup(index + 1, role, "icon-user", null, null, role, new string[0], new string[0])); - } - var mockUser = MockedUser.GetUserMock(); - mockUser.Setup(x => x.IsApproved).Returns(true); - mockUser.Setup(x => x.IsLockedOut).Returns(false); - mockUser.Setup(x => x.AllowedSections).Returns(backofficeIdentity.GetAllowedApplications()); - mockUser.Setup(x => x.Groups).Returns(groups); - mockUser.Setup(x => x.Email).Returns("admin@admin.com"); - mockUser.Setup(x => x.Id).Returns((int)backofficeIdentity.GetId()); - mockUser.Setup(x => x.Language).Returns("en"); - mockUser.Setup(x => x.Name).Returns(backofficeIdentity.GetRealName()); - mockUser.Setup(x => x.StartContentIds).Returns(backofficeIdentity.GetStartContentNodes()); - mockUser.Setup(x => x.StartMediaIds).Returns(backofficeIdentity.GetStartMediaNodes()); - mockUser.Setup(x => x.Username).Returns(backofficeIdentity.GetUsername()); - backofficeSecurity.Setup(x => x.CurrentUser) - .Returns(mockUser.Object); - - //mock Validate - backofficeSecurity.Setup(x => x.UserHasSectionAccess(It.IsAny(), It.IsAny())) - .Returns(() => true); - - var publishedSnapshot = new Mock(); - publishedSnapshot.Setup(x => x.Members).Returns(Mock.Of()); - var publishedSnapshotService = new Mock(); - publishedSnapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(publishedSnapshot.Object); - - var umbracoContextAccessor = Umbraco.Web.Composing.Current.UmbracoContextAccessor; - - var httpContextAccessor = TestHelper.GetHttpContextAccessor(httpContext); - var umbCtx = new UmbracoContext(httpContextAccessor, - publishedSnapshotService.Object, - backofficeSecurity.Object, - globalSettings, - TestHelper.GetHostingEnvironment(), - new TestVariationContextAccessor(), - TestHelper.UriUtility, - new AspNetCookieManager(httpContextAccessor)); - - //replace it - umbracoContextAccessor.UmbracoContext = umbCtx; - - var urlHelper = new Mock(); - urlHelper.Setup(provider => provider.GetUrl(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Returns(UrlInfo.Url("/hello/world/1234")); - - return CreateController(controllerType, request, umbracoContextAccessor); - } - - protected abstract ApiController CreateController(Type controllerType, HttpRequestMessage msg, IUmbracoContextAccessor umbracoContextAccessor); - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/ControllerTesting/TestStartup.cs b/tests/Umbraco.Tests/TestHelpers/ControllerTesting/TestStartup.cs deleted file mode 100644 index 408046ad9a63..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/ControllerTesting/TestStartup.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Net.Http; -using System.Web.Http; -using System.Web.Http.Dispatcher; -using System.Web.Http.ExceptionHandling; -using System.Web.Http.Tracing; -using Owin; -using Umbraco.Cms.Core.Web; -using Umbraco.Web; -using Umbraco.Web.Hosting; -using Umbraco.Web.WebApi; - -namespace Umbraco.Tests.TestHelpers.ControllerTesting -{ - /// - /// Startup class for the self-hosted web server works for OWIN and WebAPI - /// - public class TestStartup - { - private readonly Func _controllerFactory; - private readonly Action _initialize; - - public TestStartup(Action initialize, Func controllerFactory) - { - _controllerFactory = controllerFactory; - _initialize = initialize; - } - - public void Configuration(IAppBuilder app) - { - var httpConfig = new HttpConfiguration(); - - // TODO: Enable this if you can't see the errors produced - // var traceWriter = httpConfig.EnableSystemDiagnosticsTracing(); - // traceWriter.IsVerbose = true; - // traceWriter.MinimumLevel = TraceLevel.Debug; - - httpConfig.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always; - - // Add in a simple exception tracer so we can see what is causing the 500 Internal Server Error - httpConfig.Services.Add(typeof (IExceptionLogger), new TraceExceptionLogger()); - - httpConfig.Services.Replace(typeof (IAssembliesResolver), new SpecificAssemblyResolver(new[] { typeof (AspNetApplicationShutdownRegistry).Assembly })); - httpConfig.Services.Replace(typeof (IHttpControllerActivator), new TestControllerActivator(_controllerFactory)); - httpConfig.Services.Replace(typeof (IHttpControllerSelector), new NamespaceHttpControllerSelector(httpConfig)); - - //auth everything - app.AuthenticateEverything(); - - _initialize(httpConfig); - - app.UseWebApi(httpConfig); - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/ControllerTesting/TraceExceptionLogger.cs b/tests/Umbraco.Tests/TestHelpers/ControllerTesting/TraceExceptionLogger.cs deleted file mode 100644 index de7bd8fc10c3..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/ControllerTesting/TraceExceptionLogger.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Diagnostics; -using System.Web.Http.ExceptionHandling; - -namespace Umbraco.Tests.TestHelpers.ControllerTesting -{ - /// - /// Traces any errors for WebApi to the output window - /// - public class TraceExceptionLogger : ExceptionLogger - { - public override void Log(ExceptionLoggerContext context) - { - Trace.TraceError(context.ExceptionContext.Exception.ToString()); - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs b/tests/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs deleted file mode 100644 index 2aba18cfe6e7..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System; -using System.Collections.Generic; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Tests.Common.Extensions; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Tests.TestHelpers.Entities -{ - public class MockedContent - { - public static Content CreateBasicContent(IContentType contentType) - { - var content = new Content("Home", -1, contentType) { Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 }; - - content.ResetDirtyProperties(false); - - return content; - } - - public static Content CreateSimpleContent(IContentType contentType) - { - var content = new Content("Home", -1, contentType) { Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 }; - object obj = - new - { - title = "Welcome to our Home page", - bodyText = "This is the welcome message on the first page", - author = "John Doe" - }; - - content.PropertyValues(obj); - - content.ResetDirtyProperties(false); - - return content; - } - - public static Content CreateSimpleContent(IContentType contentType, string name, int parentId = -1, string culture = null, string segment = null) - { - var content = new Content(name, parentId, contentType) { CreatorId = 0, WriterId = 0 }; - object obj = - new - { - title = name + " Subpage", - bodyText = "This is a subpage", - author = "John Doe" - }; - - content.PropertyValues(obj, culture, segment); - - content.ResetDirtyProperties(false); - - return content; - } - - public static Content CreateSimpleContent(IContentType contentType, string name, IContent parent, string culture = null, string segment = null, bool setPropertyValues = true) - { - var content = new Content(name, parent, contentType, culture) { CreatorId = 0, WriterId = 0 }; - - if (setPropertyValues) - { - object obj = - new - { - title = name + " Subpage", - bodyText = "This is a subpage", - author = "John Doe" - }; - - content.PropertyValues(obj, culture, segment); - } - - content.ResetDirtyProperties(false); - - return content; - } - - public static Content CreateTextpageContent(IContentType contentType, string name, int parentId) - { - var content = new Content(name, parentId, contentType) { CreatorId = 0, WriterId = 0}; - object obj = - new - { - title = name + " textpage", - bodyText = string.Format("This is a textpage based on the {0} ContentType", contentType.Alias), - keywords = "text,page,meta", - description = "This is the meta description for a textpage" - }; - - content.PropertyValues(obj); - - content.ResetDirtyProperties(false); - - return content; - } - - public static Content CreateSimpleContentWithSpecialDatabaseTypes(IContentType contentType, string name, int parentId, string decimalValue, string intValue, DateTime datetimeValue) - { - var content = new Content(name, parentId, contentType) { CreatorId = 0, WriterId = 0 }; - object obj = new - { - decimalProperty = decimalValue, - intProperty = intValue, - datetimeProperty = datetimeValue - }; - - content.PropertyValues(obj); - content.ResetDirtyProperties(false); - return content; - } - - public static Content CreateAllTypesContent(IContentType contentType, string name, int parentId) - { - var content = new Content("Random Content Name", parentId, contentType) { Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 }; - - content.SetValue("isTrue", true); - content.SetValue("number", 42); - content.SetValue("bodyText", "Lorem Ipsum Body Text Test"); - content.SetValue("singleLineText", "Single Line Text Test"); - content.SetValue("multilineText", "Multiple lines \n in one box"); - content.SetValue("upload", "/media/1234/koala.jpg"); - content.SetValue("label", "Non-editable label"); - content.SetValue("dateTime", DateTime.Now.AddDays(-20)); - content.SetValue("colorPicker", "black"); - content.SetValue("ddlMultiple", "1234,1235"); - content.SetValue("rbList", "random"); - content.SetValue("date", DateTime.Now.AddDays(-10)); - content.SetValue("ddl", "1234"); - content.SetValue("chklist", "randomc"); - content.SetValue("contentPicker", Udi.Create(Constants.UdiEntityType.Document, new Guid("74ECA1D4-934E-436A-A7C7-36CC16D4095C")).ToString()); - content.SetValue("mediaPicker3", "[{\"key\": \"8f78ce9e-8fe0-4500-a52d-4c4f35566ba9\",\"mediaKey\": \"44CB39C8-01E5-45EB-9CF8-E70AAF2D1691\",\"crops\": [],\"focalPoint\": {\"left\": 0.5,\"top\": 0.5}}]"); - content.SetValue("memberPicker", Udi.Create(Constants.UdiEntityType.Member, new Guid("9A50A448-59C0-4D42-8F93-4F1D55B0F47D")).ToString()); - content.SetValue("multiUrlPicker", "[{\"name\":\"https://test.com\",\"url\":\"https://test.com\"}]"); - content.SetValue("tags", "this,is,tags"); - - return content; - } - - public static IEnumerable CreateTextpageContent(IContentType contentType, int parentId, int amount) - { - var list = new List(); - - for (int i = 0; i < amount; i++) - { - var name = "Textpage No-" + i; - var content = new Content(name, parentId, contentType) { CreatorId = 0, WriterId = 0 }; - object obj = - new - { - title = name + " title", - bodyText = string.Format("This is a textpage based on the {0} ContentType", contentType.Alias), - keywords = "text,page,meta", - description = "This is the meta description for a textpage" - }; - - content.PropertyValues(obj); - - content.ResetDirtyProperties(false); - - list.Add(content); - } - - return list; - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs b/tests/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs deleted file mode 100644 index 0f0a57c9eb9e..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs +++ /dev/null @@ -1,514 +0,0 @@ -using System; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Strings; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Tests.TestHelpers.Entities -{ - public class MockedContentTypes - { - public static IShortStringHelper ShortStringHelper { get; } = - new DefaultShortStringHelper(new DefaultShortStringHelperConfig()); - - public static ContentType CreateBasicContentType(string alias = "basePage", string name = "Base Page", IContentType parent = null) - { - var contentType = parent == null ? new ContentType(ShortStringHelper, -1) : new ContentType(ShortStringHelper, parent, alias); - - contentType.Alias = alias; - contentType.Name = name; - contentType.Description = "ContentType used for basic pages"; - contentType.Icon = ".sprTreeDoc3"; - contentType.Thumbnail = "doc2.png"; - contentType.SortOrder = 1; - contentType.CreatorId = 0; - contentType.Trashed = false; - - //ensure that nothing is marked as dirty - contentType.ResetDirtyProperties(false); - - return contentType; - } - - public static ContentType CreateTextPageContentType(string alias = "textPage", string name = "Text Page") - { - var contentType = new ContentType(ShortStringHelper, -1) - { - Alias = alias, - Name = name, - Description = "ContentType used for Text pages", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; - - var contentCollection = new PropertyTypeCollection(true); - contentCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext) { Alias = "title", Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = Constants.DataTypes.Textbox, LabelOnTop = true }); - contentCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.DataTypes.RichtextEditor, LabelOnTop = false }); - - var metaCollection = new PropertyTypeCollection(true); - metaCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext) { Alias = "keywords", Name = "Meta Keywords", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = Constants.DataTypes.Textbox }); - metaCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext) { Alias = "description", Name = "Meta Description", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.DataTypes.Textarea }); - - contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); - contentType.PropertyGroups.Add(new PropertyGroup(metaCollection) { Name = "Meta", SortOrder = 2 }); - - //ensure that nothing is marked as dirty - contentType.ResetDirtyProperties(false); - - contentType.SetDefaultTemplate(new Template(ShortStringHelper, "Textpage", "textpage")); - - return contentType; - } - - public static ContentType CreateMetaContentType() - { - var contentType = new ContentType(ShortStringHelper, -1) - { - Alias = "meta", - Name = "Meta", - Description = "ContentType used for Meta tags", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; - - var metaCollection = new PropertyTypeCollection(true); - metaCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext) { Alias = "metakeywords", Name = "Meta Keywords", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); - metaCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext) { Alias = "metadescription", Name = "Meta Description", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = -89 }); - - contentType.PropertyGroups.Add(new PropertyGroup(metaCollection) { Name = "Meta", SortOrder = 2 }); - - //ensure that nothing is marked as dirty - contentType.ResetDirtyProperties(false); - - return contentType; - } - - public static ContentType CreateContentMetaContentType() - { - var contentType = new ContentType(ShortStringHelper, -1) - { - Alias = "contentMeta", - Name = "Content Meta", - Description = "ContentType used for Content Meta", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; - - var metaCollection = new PropertyTypeCollection(true); - metaCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext) { Alias = "title", Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); - - contentType.PropertyGroups.Add(new PropertyGroup(metaCollection) { Name = "Content", SortOrder = 2 }); - - //ensure that nothing is marked as dirty - contentType.ResetDirtyProperties(false); - - return contentType; - } - - public static ContentType CreateSeoContentType() - { - var contentType = new ContentType(ShortStringHelper, -1) - { - Alias = "seo", - Name = "Seo", - Description = "ContentType used for Seo", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; - - var metaCollection = new PropertyTypeCollection(true); - metaCollection.Add(new PropertyType(ShortStringHelper, "seotest", ValueStorageType.Ntext) { Alias = "seokeywords", Name = "Seo Keywords", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); - metaCollection.Add(new PropertyType(ShortStringHelper, "seotest", ValueStorageType.Ntext) { Alias = "seodescription", Name = "Seo Description", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = -89 }); - - contentType.PropertyGroups.Add(new PropertyGroup(metaCollection) { Name = "Seo", SortOrder = 5 }); - - //ensure that nothing is marked as dirty - contentType.ResetDirtyProperties(false); - - return contentType; - } - - public static ContentType CreateSimpleContentType() - { - var contentType = new ContentType(ShortStringHelper, -1) - { - Alias = "simple", - Name = "Simple Page", - Description = "ContentType used for simple text pages", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; - - var contentCollection = new PropertyTypeCollection(true); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = "title", Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TinyMce, ValueStorageType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = -87 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = "author", Name = "Author", Description = "Name of the author", Mandatory = false, SortOrder = 3, DataTypeId = -88 }); - - contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) - { - Name = "Content", - Alias = "content", - SortOrder = 1 - }); - - //ensure that nothing is marked as dirty - contentType.ResetDirtyProperties(false); - - return contentType; - } - - public static ContentType CreateSimpleContentType3(string alias, string name, IContentType parent = null, bool randomizeAliases = false, string propertyGroupName = "Content") - { - var contentType = CreateSimpleContentType(alias, name, parent, randomizeAliases, propertyGroupName); - - var propertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Tags, ValueStorageType.Nvarchar) - { - Alias = RandomAlias("tags", randomizeAliases), - Name = "Tags", - Description = "Tags", - Mandatory = false, - SortOrder = 99, - DataTypeId = Constants.DataTypes.Tags - }; - contentType.AddPropertyType(propertyType); - - return contentType; - } - - - - public static ContentType CreateSimpleContentType(string alias, string name, IContentType parent = null, bool randomizeAliases = false, string propertyGroupName = "Content") - { - var contentType = parent == null ? new ContentType(ShortStringHelper, -1) : new ContentType(ShortStringHelper, parent, alias); - - contentType.Alias = alias; - contentType.Name = name; - contentType.Description = "ContentType used for simple text pages"; - contentType.Icon = ".sprTreeDoc3"; - contentType.Thumbnail = "doc2.png"; - contentType.SortOrder = 1; - contentType.CreatorId = 0; - contentType.Trashed = false; - - var contentCollection = new PropertyTypeCollection(true); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = RandomAlias("title", randomizeAliases), Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88, LabelOnTop = true }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TinyMce, ValueStorageType.Ntext) { Alias = RandomAlias("bodyText", randomizeAliases), Name = "Body Text", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = -87 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = RandomAlias("author", randomizeAliases) , Name = "Author", Description = "Name of the author", Mandatory = false, SortOrder = 3, DataTypeId = -88 }); - - var pg = new PropertyGroup(contentCollection) - { - Name = propertyGroupName, - SortOrder = 1 - }; - contentType.PropertyGroups.Add(pg); - - //ensure that nothing is marked as dirty - contentType.ResetDirtyProperties(false); - - contentType.SetDefaultTemplate(new Template(ShortStringHelper, "Textpage", "textpage")); - - return contentType; - } - - public static MediaType CreateSimpleMediaType(string alias, string name, IMediaType parent = null, bool randomizeAliases = false, string propertyGroupName = "Content") - { - var contentType = parent == null ? new MediaType(ShortStringHelper, -1) : new MediaType(ShortStringHelper, parent, alias); - - contentType.Alias = alias; - contentType.Name = name; - contentType.Description = "ContentType used for simple text pages"; - contentType.Icon = ".sprTreeDoc3"; - contentType.Thumbnail = "doc2.png"; - contentType.SortOrder = 1; - contentType.CreatorId = 0; - contentType.Trashed = false; - - var contentCollection = new PropertyTypeCollection(false); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = RandomAlias("title", randomizeAliases), Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TinyMce, ValueStorageType.Ntext) { Alias = RandomAlias("bodyText", randomizeAliases), Name = "Body Text", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = -87 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = RandomAlias("author", randomizeAliases), Name = "Author", Description = "Name of the author", Mandatory = false, SortOrder = 3, DataTypeId = -88 }); - - var pg = new PropertyGroup(contentCollection) { Name = propertyGroupName, SortOrder = 1 }; - contentType.PropertyGroups.Add(pg); - - //ensure that nothing is marked as dirty - contentType.ResetDirtyProperties(false); - - return contentType; - } - - public static ContentType CreateSimpleContentType(string alias, string name, bool mandatory) - { - var contentType = new ContentType(ShortStringHelper, -1) - { - Alias = alias, - Name = name, - Description = "ContentType used for simple text pages", - Icon = ".sprTreeDoc3", - Thumbnail = "doc2.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; - - var contentCollection = new PropertyTypeCollection(true); - contentCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext) { Alias = "title", Name = "Title", Description = "", Mandatory = mandatory, SortOrder = 1, DataTypeId = -88 }); - contentCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", Mandatory = mandatory, SortOrder = 2, DataTypeId = -87 }); - contentCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext) { Alias = "author", Name = "Author", Description = "Name of the author", Mandatory = mandatory, SortOrder = 3, DataTypeId = -88 }); - - contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); - - //ensure that nothing is marked as dirty - contentType.ResetDirtyProperties(false); - - return contentType; - } - - public static ContentType CreateSimpleContentType(string alias, string name, PropertyTypeCollection collection) - { - var contentType = new ContentType(ShortStringHelper, -1) - { - Alias = alias, - Name = name, - Description = "ContentType used for simple text pages", - Icon = ".sprTreeDoc3", - Thumbnail = "doc3.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; - - contentType.PropertyGroups.Add(new PropertyGroup(collection) { Name = "Content", SortOrder = 1 }); - - //ensure that nothing is marked as dirty - contentType.ResetDirtyProperties(false); - - return contentType; - } - - public static ContentType CreateSimpleContentType(string alias, string name, PropertyTypeCollection collection, string propertyGroupName, IContentType parent = null) - { - var contentType = parent == null ? new ContentType(ShortStringHelper, -1) : new ContentType(ShortStringHelper, parent, alias); - - contentType.Alias = alias; - contentType.Name = name; - contentType.Description = "ContentType used for simple text pages"; - contentType.Icon = ".sprTreeDoc3"; - contentType.Thumbnail = "doc2.png"; - contentType.SortOrder = 1; - contentType.CreatorId = 0; - contentType.Trashed = false; - - contentType.PropertyGroups.Add(new PropertyGroup(collection) { Name = propertyGroupName, SortOrder = 1 }); - - //ensure that nothing is marked as dirty - contentType.ResetDirtyProperties(false); - - return contentType; - } - - public static ContentType CreateSimpleContentType(string alias, string name, PropertyTypeCollection groupedCollection, PropertyTypeCollection nonGroupedCollection) - { - var contentType = CreateSimpleContentType(alias, name, groupedCollection); - //now add the non-grouped properties - foreach (var x in nonGroupedCollection) - contentType.AddPropertyType(x); - - //ensure that nothing is marked as dirty - contentType.ResetDirtyProperties(false); - - return contentType; - } - - public static ContentType CreateAllTypesContentType(string alias, string name) - { - var contentType = new ContentType(ShortStringHelper, -1) - { - Alias = alias, - Name = name, - Description = "ContentType containing all standard DataTypes", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; - - var contentCollection = new PropertyTypeCollection(true); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Boolean, ValueStorageType.Integer) { Alias = "isTrue", Name = "Is True or False", Mandatory = false, SortOrder = 1, DataTypeId = -49 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer) { Alias = "number", Name = "Number", Mandatory = false, SortOrder = 2, DataTypeId = -51 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TinyMce, ValueStorageType.Ntext) { Alias = "bodyText", Name = "Body Text", Mandatory = false, SortOrder = 3, DataTypeId = -87 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Nvarchar) { Alias = "singleLineText", Name = "Text String", Mandatory = false, SortOrder = 4, DataTypeId = -88 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextArea, ValueStorageType.Ntext) { Alias = "multilineText", Name = "Multiple Text Strings", Mandatory = false, SortOrder = 5, DataTypeId = -89 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.UploadField, ValueStorageType.Nvarchar) { Alias = "upload", Name = "Upload Field", Mandatory = false, SortOrder = 6, DataTypeId = -90 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar) { Alias = "label", Name = "Label", Mandatory = false, SortOrder = 7, DataTypeId = -92 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.DateTime, ValueStorageType.Date) { Alias = "dateTime", Name = "Date Time", Mandatory = false, SortOrder = 8, DataTypeId = -36 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.ColorPicker, ValueStorageType.Nvarchar) { Alias = "colorPicker", Name = "Color Picker", Mandatory = false, SortOrder = 9, DataTypeId = -37 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.DropDownListFlexible, ValueStorageType.Nvarchar) { Alias = "ddlMultiple", Name = "Dropdown List Multiple", Mandatory = false, SortOrder = 11, DataTypeId = -39 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.RadioButtonList, ValueStorageType.Nvarchar) { Alias = "rbList", Name = "Radio Button List", Mandatory = false, SortOrder = 12, DataTypeId = -40 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.DateTime, ValueStorageType.Date) { Alias = "date", Name = "Date", Mandatory = false, SortOrder = 13, DataTypeId = -36 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.DropDownListFlexible, ValueStorageType.Integer) { Alias = "ddl", Name = "Dropdown List", Mandatory = false, SortOrder = 14, DataTypeId = -42 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.CheckBoxList, ValueStorageType.Nvarchar) { Alias = "chklist", Name = "Checkbox List", Mandatory = false, SortOrder = 15, DataTypeId = -43 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.ContentPicker, ValueStorageType.Integer) { Alias = "contentPicker", Name = "Content Picker", Mandatory = false, SortOrder = 16, DataTypeId = 1046 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.MediaPicker3, ValueStorageType.Integer) { Alias = "mediapicker3", Name = "Media Picker", Mandatory = false, SortOrder = 17, DataTypeId = 1051 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.MemberPicker, ValueStorageType.Integer) { Alias = "memberPicker", Name = "Member Picker", Mandatory = false, SortOrder = 18, DataTypeId = 1047 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.MultiUrlPicker, ValueStorageType.Nvarchar) { Alias = "multiUrlPicker", Name = "Multi URL Picker", Mandatory = false, SortOrder = 21, DataTypeId = 1050 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Tags, ValueStorageType.Ntext) { Alias = "tags", Name = "Tags", Mandatory = false, SortOrder = 22, DataTypeId = 1041 }); - - contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); - - return contentType; - } - - public static MediaType CreateNewMediaType() - { - var mediaType = new MediaType(ShortStringHelper, -1) - { - Alias = "newMediaType", - Name = "New Media Type", - Description = "ContentType used for a new format", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; - - var contentCollection = new PropertyTypeCollection(false); - contentCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext) { Alias = "title", Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); - contentCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Nvarchar) { Alias = "videoFile", Name = "Video File", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = -90 }); - - mediaType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Media", SortOrder = 1 }); - - //ensure that nothing is marked as dirty - mediaType.ResetDirtyProperties(false); - - return mediaType; - } - - public static MediaType CreateImageMediaType(string alias = Constants.Conventions.MediaTypes.Image) - { - var mediaType = new MediaType(ShortStringHelper, -1) - { - Alias = alias, - Name = "Image", - Description = "ContentType used for images", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; - - var contentCollection = new PropertyTypeCollection(false); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.UploadField, ValueStorageType.Nvarchar) { Alias = Constants.Conventions.Media.File, Name = "File", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -90 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Width, Name = "Width", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Height, Name = "Height", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Bytes, Name = "Bytes", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar) { Alias = Constants.Conventions.Media.Extension, Name = "File Extension", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId }); - - mediaType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Media", SortOrder = 1 }); - - //ensure that nothing is marked as dirty - mediaType.ResetDirtyProperties(false); - - return mediaType; - } - - public static MediaType CreateImageMediaTypeWithCrop(string alias = Constants.Conventions.MediaTypes.Image) - { - var mediaType = new MediaType(ShortStringHelper, -1) - { - Alias = alias, - Name = "Image", - Description = "ContentType used for images", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; - - var contentCollection = new PropertyTypeCollection(false); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.ImageCropper, ValueStorageType.Ntext) { Alias = Constants.Conventions.Media.File, Name = "File", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = 1043 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Width, Name = "Width", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Height, Name = "Height", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Bytes, Name = "Bytes", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar) { Alias = Constants.Conventions.Media.Extension, Name = "File Extension", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId }); - - mediaType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Media", SortOrder = 1 }); - - //ensure that nothing is marked as dirty - mediaType.ResetDirtyProperties(false); - - return mediaType; - } - - public static MemberType CreateSimpleMemberType(string alias = null, string name = null) - { - var contentType = new MemberType(ShortStringHelper, -1) - { - Alias = alias ?? "simple", - Name = name ?? "Simple Page", - Description = "Some member type", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; - - var contentCollection = new PropertyTypeCollection(false); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = "title", Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = -87 }); - contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = "author", Name = "Author", Description = "Name of the author", Mandatory = false, SortOrder = 3, DataTypeId = -88 }); - - contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); - - //ensure that nothing is marked as dirty - contentType.ResetDirtyProperties(false); - - return contentType; - } - - public static void EnsureAllIds(ContentTypeCompositionBase contentType, int seedId) - { - //ensure everything has ids - contentType.Id = seedId; - var itemid = seedId + 1; - foreach (var propertyGroup in contentType.PropertyGroups) - { - propertyGroup.Id = itemid++; - } - foreach (var propertyType in contentType.PropertyTypes) - { - propertyType.Id = itemid++; - } - } - - - private static string RandomAlias(string alias, bool randomizeAliases) - { - if (randomizeAliases) - { - return string.Concat(alias, Guid.NewGuid().ToString("N")); - } - - return alias; - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/Entities/MockedEntity.cs b/tests/Umbraco.Tests/TestHelpers/Entities/MockedEntity.cs deleted file mode 100644 index c40d5b33bf8d..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/Entities/MockedEntity.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Runtime.Serialization; -using Umbraco.Cms.Core.Models.Entities; - -namespace Umbraco.Tests.TestHelpers.Entities -{ - [Serializable] - [DataContract(IsReference = true)] - public class MockedEntity : EntityBase - { - [DataMember] - public string Alias { get; set; } - - [DataMember] - public string Name { get; set; } - - [DataMember] - public string Value { get; set; } - } - - public class CustomMockedEntity : MockedEntity - { - [DataMember] - public string Title { get; set; } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/Entities/MockedMedia.cs b/tests/Umbraco.Tests/TestHelpers/Entities/MockedMedia.cs deleted file mode 100644 index 2d8bcc63951a..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/Entities/MockedMedia.cs +++ /dev/null @@ -1,85 +0,0 @@ -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Tests.Common.Extensions; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Tests.TestHelpers.Entities -{ - public static class MockedMedia - { - public static Media CreateSimpleMedia(IMediaType contentType, string name, int parentId) - { - var content = new Media(name, parentId, contentType) { CreatorId = 0 }; - object obj = - new - { - title = name + " Subpage", - bodyText = "This is a subpage", - author = "John Doe" - }; - - content.PropertyValues(obj); - - content.ResetDirtyProperties(false); - - return content; - } - - public static Media CreateMediaImage(IMediaType mediaType, int parentId) - { - var media = new Media("Test Image", parentId, mediaType) - { - CreatorId = 0 - }; - - media.SetValue(Constants.Conventions.Media.File, "/media/test-image.png"); - media.SetValue(Constants.Conventions.Media.Width, "200"); - media.SetValue(Constants.Conventions.Media.Height, "200"); - media.SetValue(Constants.Conventions.Media.Bytes, "100"); - media.SetValue(Constants.Conventions.Media.Extension, "png"); - - return media; - } - - public static Media CreateMediaFile(IMediaType mediaType, int parentId) - { - var media = new Media("Test File", parentId, mediaType) - { - CreatorId = 0 - }; - - media.SetValue(Constants.Conventions.Media.File, "/media/test-file.txt"); - media.SetValue(Constants.Conventions.Media.Bytes, "4"); - media.SetValue(Constants.Conventions.Media.Extension, "txt"); - - return media; - } - - public static Media CreateMediaImageWithCrop(IMediaType mediaType, int parentId) - { - var media = new Media("Test Image", parentId, mediaType) - { - CreatorId = 0 - }; - - media.SetValue(Constants.Conventions.Media.File, "{src: '/media/test-image.png', crops: []}"); - media.SetValue(Constants.Conventions.Media.Width, "200"); - media.SetValue(Constants.Conventions.Media.Height, "200"); - media.SetValue(Constants.Conventions.Media.Bytes, "100"); - media.SetValue(Constants.Conventions.Media.Extension, "png"); - - - - return media; - } - - public static Media CreateMediaFolder(IMediaType mediaType, int parentId) - { - var media = new Media("Test Folder", parentId, mediaType) - { - CreatorId = 0 - }; - - return media; - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/Entities/MockedMember.cs b/tests/Umbraco.Tests/TestHelpers/Entities/MockedMember.cs deleted file mode 100644 index bc9dcf175097..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/Entities/MockedMember.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using Umbraco.Cms.Core.Models; - -namespace Umbraco.Tests.TestHelpers.Entities -{ - public class MockedMember - { - public static Member CreateSimpleMember(IMemberType contentType, string name, string email, string password, string username, Guid? key = null) - { - var member = new Member(name, email, username, password, contentType) - { - CreatorId = 0, - Email = email, - RawPasswordValue = password, - Username = username - }; - - if (key.HasValue) - { - member.Key = key.Value; - } - - member.SetValue("title", name + " member"); - member.SetValue("bodyText", "This is a subpage"); - member.SetValue("author", "John Doe"); - - member.ResetDirtyProperties(false); - - return member; - } - - public static Member CreateSimpleMember(IMemberType contentType, string name, string email, string username, Guid? key = null) - { - var member = new Member(name, email, username, contentType) - { - CreatorId = 0, - Email = email, - Username = username - }; - - if (key.HasValue) - { - member.Key = key.Value; - } - - member.SetValue("title", name + " member"); - member.SetValue("bodyText", "This is a subpage"); - member.SetValue("author", "John Doe"); - - member.ResetDirtyProperties(false); - - return member; - } - - public static IEnumerable CreateSimpleMember(IMemberType memberType, int amount, Action onCreating = null) - { - var list = new List(); - - for (int i = 0; i < amount; i++) - { - var name = "Member No-" + i; - var member = new Member(name, "test" + i + "@test.com", "test" + i, "test" + i, memberType); - member.SetValue("title", name + " member" + i); - member.SetValue("bodyText", "This is a subpage" + i); - member.SetValue("author", "John Doe" + i); - - if (onCreating != null) - { - onCreating(i, member); - } - - member.ResetDirtyProperties(false); - - list.Add(member); - } - - return list; - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/Entities/MockedPropertyTypes.cs b/tests/Umbraco.Tests/TestHelpers/Entities/MockedPropertyTypes.cs deleted file mode 100644 index a2d137800e41..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/Entities/MockedPropertyTypes.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Umbraco.Cms.Core.Models; - -namespace Umbraco.Tests.TestHelpers.Entities -{ - public class MockedPropertyTypes - { - /// - /// Returns a decimal property. - /// Requires a datatype definition Id, since this is not one of the pre-populated datatypes - /// - /// Alias of the created property type - /// Name of the created property type - /// Integer Id of a decimal datatype to use - /// Property type storing decimal value - public static PropertyType CreateDecimalProperty(string alias, string name, int dtdId) - { - return - new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Decimal, alias) - { - Name = name, - Description = "Decimal property type", - Mandatory = false, - SortOrder = 4, - DataTypeId = dtdId - }; - } - - /// - /// Returns a integer property. - /// - /// Alias of the created property type - /// Name of the created property type - /// Property type storing integer value - public static PropertyType CreateIntegerProperty(string alias, string name) - { - return - new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Integer, alias) - { - Name = name, - Description = "Integer property type", - Mandatory = false, - SortOrder = 4, - DataTypeId = -51 - }; - } - - /// - /// Returns a DateTime property. - /// - /// Alias of the created property type - /// Name of the created property type - /// Property type storing DateTime value - public static PropertyType CreateDateTimeProperty(string alias, string name) - { - return - new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Date, alias) - { - Name = name, - Description = "DateTime property type", - Mandatory = false, - SortOrder = 4, - DataTypeId = -36 - }; - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs b/tests/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs deleted file mode 100644 index f2fbaca57168..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Collections.Generic; -using Moq; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Models.Membership; - -namespace Umbraco.Tests.TestHelpers.Entities -{ - public class MockedUser - { - /// - /// Returns a and ensures that the ToUserCache and FromUserCache methods are mapped correctly for - /// dealing with start node caches - /// - /// - internal static Mock GetUserMock() - { - var userCache = new Dictionary(); - var userMock = new Mock(); - userMock.Setup(x => x.FromUserCache(It.IsAny())).Returns((string key) => userCache.TryGetValue(key, out var val) ? val is int[] iVal ? iVal : null : null); - userMock.Setup(x => x.ToUserCache(It.IsAny(), It.IsAny())).Callback((string key, int[] val) => userCache[key] = val); - return userMock; - } - - internal static User CreateUser(string suffix = "") - { - var globalSettings = new GlobalSettings(); - var user = new User(globalSettings) - { - Language = "en", - IsApproved = true, - Name = "TestUser" + suffix, - RawPasswordValue = "testing", - IsLockedOut = false, - Email = "test" + suffix + "@test.com", - Username = "TestUser" + suffix - }; - - return user; - } - - internal static IEnumerable CreateMulipleUsers(int amount, Action onCreating = null) - { - var list = new List(); - - var globalSettings = new GlobalSettings(); - for (int i = 0; i < amount; i++) - { - var name = "Member No-" + i; - var user = new User(globalSettings, name, "test" + i + "@test.com", "test" + i, "test" + i); - - onCreating?.Invoke(i, user); - - user.ResetDirtyProperties(false); - - list.Add(user); - } - - return list; - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/Entities/MockedUserGroup.cs b/tests/Umbraco.Tests/TestHelpers/Entities/MockedUserGroup.cs deleted file mode 100644 index 37a510a0e8ad..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/Entities/MockedUserGroup.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Umbraco.Cms.Core.Models.Membership; -using Umbraco.Cms.Core.Strings; - -namespace Umbraco.Tests.TestHelpers.Entities -{ - public class MockedUserGroup - { - public static IShortStringHelper ShortStringHelper { get; } = - new DefaultShortStringHelper(new DefaultShortStringHelperConfig()); - - public static UserGroup CreateUserGroup(string suffix = "", string[] permissions = null, string[] allowedSections = null) - { - var group = new UserGroup(ShortStringHelper) - { - Alias = "testUserGroup" + suffix, - Name = "TestUserGroup" + suffix, - Permissions = permissions ?? new[] { "A", "B", "C" } - }; - - if (allowedSections == null) - { - group.AddAllowedSection("content"); - group.AddAllowedSection("media"); - } - else - { - foreach (var allowedSection in allowedSections) - { - group.AddAllowedSection(allowedSection); - } - } - - return group; - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/FakeHttpContextFactory.cs b/tests/Umbraco.Tests/TestHelpers/FakeHttpContextFactory.cs deleted file mode 100644 index bcbbdab59849..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/FakeHttpContextFactory.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Specialized; -using System.Security; -using System.Security.Principal; -using System.Web; -using System.Web.Routing; -using Moq; - -namespace Umbraco.Tests.TestHelpers -{ - /// - /// Creates a mock http context with supporting other contexts to test against - /// - public class FakeHttpContextFactory - { - - [SecuritySafeCritical] - public FakeHttpContextFactory(Uri fullUrl) - { - CreateContext(fullUrl); - } - - [SecuritySafeCritical] - public FakeHttpContextFactory(string path) - { - if (path.StartsWith("http://") || path.StartsWith("https://")) - CreateContext(new Uri(path)); - else - CreateContext(new Uri("http://mysite" + VirtualPathUtility.ToAbsolute(path, "/"))); - } - - [SecuritySafeCritical] - public FakeHttpContextFactory(string path, RouteData routeData) - { - if (path.StartsWith("http://") || path.StartsWith("https://")) - CreateContext(new Uri(path), routeData); - else - CreateContext(new Uri("http://mysite" + VirtualPathUtility.ToAbsolute(path, "/")), routeData); - } - - public HttpContextBase HttpContext { get; private set; } - public RequestContext RequestContext { get; private set; } - - /// - /// Mocks the http context to test against - /// - /// - /// - /// - private void CreateContext(Uri fullUrl, RouteData routeData = null) - { - //Request context - - var requestContextMock = new Mock(); - - RequestContext = requestContextMock.Object; - - //Cookie collection - var cookieCollection = new HttpCookieCollection(); - cookieCollection.Add(new HttpCookie("UMB_UCONTEXT", "FBA996E7-D6BE-489B-B199-2B0F3D2DD826")); - - //Request - var requestMock = new Mock(); - requestMock.Setup(x => x.AppRelativeCurrentExecutionFilePath).Returns("~" + fullUrl.AbsolutePath); - requestMock.Setup(x => x.PathInfo).Returns(string.Empty); - requestMock.Setup(x => x.RawUrl).Returns(VirtualPathUtility.ToAbsolute("~" + fullUrl.AbsolutePath, "/")); - requestMock.Setup(x => x.RequestContext).Returns(RequestContext); - requestMock.Setup(x => x.Url).Returns(fullUrl); - requestMock.Setup(x => x.ApplicationPath).Returns("/"); - requestMock.Setup(x => x.Cookies).Returns(cookieCollection); - requestMock.Setup(x => x.ServerVariables).Returns(new NameValueCollection()); - var queryStrings = HttpUtility.ParseQueryString(fullUrl.Query); - requestMock.Setup(x => x.QueryString).Returns(queryStrings); - requestMock.Setup(x => x.Form).Returns(new NameValueCollection()); - - //Cache - var cacheMock = new Mock(); - - //Response - //var response = new FakeHttpResponse(); - var responseMock = new Mock(); - responseMock.Setup(x => x.ApplyAppPathModifier(It.IsAny())).Returns((string s) => s); - responseMock.Setup(x => x.Cache).Returns(cacheMock.Object); - - //Server - - var serverMock = new Mock(); - serverMock.Setup(x => x.MapPath(It.IsAny())).Returns(Environment.CurrentDirectory); - - //User - var user = new Mock().Object; - - //HTTP Context - - var httpContextMock = new Mock(); - httpContextMock.Setup(x => x.Cache).Returns(HttpRuntime.Cache); - //note: foreach on Items should return DictionaryEntries! - //httpContextMock.Setup(x => x.Items).Returns(new Dictionary()); - httpContextMock.Setup(x => x.Items).Returns(new Hashtable()); - httpContextMock.Setup(x => x.Request).Returns(requestMock.Object); - httpContextMock.Setup(x => x.Server).Returns(serverMock.Object); - httpContextMock.Setup(x => x.Response).Returns(responseMock.Object); - httpContextMock.Setup(x => x.User).Returns(user); - - HttpContext = httpContextMock.Object; - - requestContextMock.Setup(x => x.HttpContext).Returns(httpContextMock.Object); - - - if (routeData is null) - { - routeData = new RouteData(); - } - - requestContextMock.Setup(x => x.RouteData).Returns(routeData); - } - - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs b/tests/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs deleted file mode 100644 index cf8820828669..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Web.Mvc; -using System.Web.Routing; -using System.Web.SessionState; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Web; -using Umbraco.Extensions; -using Current = Umbraco.Web.Composing.Current; - -namespace Umbraco.Tests.TestHelpers.Stubs -{ - /// - /// Used in place of the UmbracoControllerFactory which relies on BuildManager which throws exceptions in a unit test context - /// - internal class TestControllerFactory : IControllerFactory - { - private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly ILogger _logger; - private readonly Func _factory; - - public TestControllerFactory(IUmbracoContextAccessor umbracoContextAccessor, ILogger logger) - { - _umbracoContextAccessor = umbracoContextAccessor; - _logger = logger; - } - - public TestControllerFactory(IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, Func factory) - { - _umbracoContextAccessor = umbracoContextAccessor; - _logger = logger; - _factory = factory; - } - - public IController CreateController(RequestContext requestContext, string controllerName) - { - if (_factory != null) return _factory(requestContext); - - var typeFinder = TestHelper.GetTypeFinder(); - var types = typeFinder.FindClassesOfType(new[] { Assembly.GetExecutingAssembly() }); - - var controllerTypes = types.Where(x => x.Name.Equals(controllerName + "Controller", StringComparison.InvariantCultureIgnoreCase)); - var t = controllerTypes.SingleOrDefault(); - - if (t == null) - return null; - - var possibleParams = new object[] - { - _umbracoContextAccessor, _logger - }; - var ctors = t.GetConstructors(); - foreach (var ctor in ctors.OrderByDescending(x => x.GetParameters().Length)) - { - var args = new List(); - var allParams = ctor.GetParameters().ToArray(); - foreach (var parameter in allParams) - { - var found = possibleParams.SingleOrDefault(x => x.GetType() == parameter.ParameterType) - ?? Current.Factory.GetRequiredService(parameter.ParameterType); - if (found != null) args.Add(found); - } - if (args.Count == allParams.Length) - { - return Activator.CreateInstance(t, args.ToArray()) as IController; - } - } - return null; - } - - public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName) - { - return SessionStateBehavior.Disabled; - } - - public void ReleaseController(IController controller) - { - controller.DisposeIfDisposable(); - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/Stubs/TestExamineManager.cs b/tests/Umbraco.Tests/TestHelpers/Stubs/TestExamineManager.cs deleted file mode 100644 index 7bb3b90d8156..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/Stubs/TestExamineManager.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Collections.Concurrent; -using System.Collections.Generic; -using Examine; - -namespace Umbraco.Tests.TestHelpers.Stubs -{ - internal class TestExamineManager : IExamineManager - { - private readonly ConcurrentDictionary _indexers = new ConcurrentDictionary(); - private readonly ConcurrentDictionary _searchers = new ConcurrentDictionary(); - - public IIndex AddIndex(IIndex indexer) - { - _indexers.TryAdd(indexer.Name, indexer); - return indexer; - } - - public ISearcher AddSearcher(ISearcher searcher) - { - _searchers.TryAdd(searcher.Name, searcher); - return searcher; - } - - public void Dispose() - { - //noop - } - - public bool TryGetIndex(string indexName, out IIndex index) - { - return _indexers.TryGetValue(indexName, out index); - } - - public bool TryGetSearcher(string searcherName, out ISearcher searcher) - { - return _searchers.TryGetValue(searcherName, out searcher); - } - - public IEnumerable Indexes => _indexers.Values; - - public IEnumerable RegisteredSearchers => _searchers.Values; - - public IReadOnlyDictionary IndexProviders => _indexers; - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/Stubs/TestLastChanceFinder.cs b/tests/Umbraco.Tests/TestHelpers/Stubs/TestLastChanceFinder.cs deleted file mode 100644 index 89798b877132..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/Stubs/TestLastChanceFinder.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Umbraco.Cms.Core.Routing; - -namespace Umbraco.Tests.TestHelpers.Stubs -{ - internal class TestLastChanceFinder : IContentLastChanceFinder - { - public bool TryFindContent(IPublishedRequestBuilder frequest) => false; - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/Stubs/TestUserPasswordConfig.cs b/tests/Umbraco.Tests/TestHelpers/Stubs/TestUserPasswordConfig.cs deleted file mode 100644 index 065305c63a76..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/Stubs/TestUserPasswordConfig.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Umbraco.Cms.Core.Configuration; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Tests.TestHelpers.Stubs -{ - internal class TestUserPasswordConfig : IUserPasswordConfiguration - { - public int RequiredLength => 12; - - public bool RequireNonLetterOrDigit => false; - - public bool RequireDigit => false; - - public bool RequireLowercase => false; - - public bool RequireUppercase => false; - - public bool UseLegacyEncoding => false; - - public string HashAlgorithmType => Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName; - - public int MaxFailedAccessAttemptsBeforeLockout => 5; - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/TestHelper.cs b/tests/Umbraco.Tests/TestHelpers/TestHelper.cs deleted file mode 100644 index b8960c6b64e1..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/TestHelper.cs +++ /dev/null @@ -1,346 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading; -using System.Web; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Configuration; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Diagnostics; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Mail; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.Entities; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Net; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Runtime; -using Umbraco.Cms.Core.Serialization; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Infrastructure; -using Umbraco.Cms.Infrastructure.Migrations.Install; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Persistence.SqlCe; -using Umbraco.Cms.Tests.Common; -using Umbraco.Extensions; -using Umbraco.Web; -using Umbraco.Web.Hosting; -using Constants = Umbraco.Cms.Core.Constants; -using File = System.IO.File; - -namespace Umbraco.Tests.TestHelpers -{ - /// - /// Common helper properties and methods useful to testing - /// - public static class TestHelper - { - private static readonly TestHelperInternal _testHelperInternal = new TestHelperInternal(); - private static IEmailSender _emailSender; - - private class TestHelperInternal : TestHelperBase - { - public TestHelperInternal() : base(typeof(TestHelperInternal).Assembly) - { - - } - - public override IDbProviderFactoryCreator DbProviderFactoryCreator { get; } = new UmbracoDbProviderFactoryCreator(); - public DatabaseSchemaCreatorFactory DatabaseSchemaCreatorFactory { get; } = new DatabaseSchemaCreatorFactory(Mock.Of>(), NullLoggerFactory.Instance, new UmbracoVersion(), Mock.Of()); - - public override IBulkSqlInsertProvider BulkSqlInsertProvider { get; } = new SqlCeBulkSqlInsertProvider(); - - public override IMarchal Marchal { get; } = new FrameworkMarchal(); - - public override IHostingEnvironment GetHostingEnvironment() - => new AspNetHostingEnvironment(Options.Create(new HostingSettings())); - - public override IApplicationShutdownRegistry GetHostingEnvironmentLifetime() - => new AspNetApplicationShutdownRegistry(); - - public override IIpResolver GetIpResolver() - => new AspNetIpResolver(); - } - - public static ITypeFinder GetTypeFinder() => _testHelperInternal.GetTypeFinder(); - - public static TypeLoader GetMockedTypeLoader() => _testHelperInternal.GetMockedTypeLoader(); - - /// - /// Gets the working directory of the test project. - /// - /// The assembly directory. - public static string WorkingDirectory => _testHelperInternal.WorkingDirectory; - - public static IShortStringHelper ShortStringHelper => _testHelperInternal.ShortStringHelper; - public static IJsonSerializer JsonSerializer => _testHelperInternal.JsonSerializer; - public static IVariationContextAccessor VariationContextAccessor => _testHelperInternal.VariationContextAccessor; - public static IDbProviderFactoryCreator DbProviderFactoryCreator => _testHelperInternal.DbProviderFactoryCreator; - public static DatabaseSchemaCreatorFactory DatabaseSchemaCreatorFactory => _testHelperInternal.DatabaseSchemaCreatorFactory; - public static IBulkSqlInsertProvider BulkSqlInsertProvider => _testHelperInternal.BulkSqlInsertProvider; - public static IMarchal Marchal => _testHelperInternal.Marchal; - public static CoreDebugSettings CoreDebugSettings => _testHelperInternal.CoreDebugSettings; - - - public static IIOHelper IOHelper => _testHelperInternal.IOHelper; - public static IMainDom MainDom => _testHelperInternal.MainDom; - public static UriUtility UriUtility => _testHelperInternal.UriUtility; - - public static IEmailSender EmailSender { get; } = new EmailSender(Options.Create(new GlobalSettings())); - - - /// - /// Some test files are copied to the /bin (/bin/debug) on build, this is a utility to return their physical path based on a virtual path name - /// - /// - /// - public static string MapPathForTestFiles(string relativePath) => _testHelperInternal.MapPathForTestFiles(relativePath); - - public static void InitializeContentDirectories() - { - CreateDirectories(new[] { Constants.SystemDirectories.MvcViews, new GlobalSettings().UmbracoMediaPath, Constants.SystemDirectories.AppPlugins }); - } - - public static void CleanContentDirectories() - { - CleanDirectories(new[] { Constants.SystemDirectories.MvcViews, new GlobalSettings().UmbracoMediaPath }); - } - - public static void CreateDirectories(string[] directories) - { - foreach (var directory in directories) - { - var directoryInfo = new DirectoryInfo(IOHelper.MapPath(directory)); - if (directoryInfo.Exists == false) - Directory.CreateDirectory(IOHelper.MapPath(directory)); - } - } - - public static void CleanDirectories(string[] directories) - { - var preserves = new Dictionary - { - { Constants.SystemDirectories.MvcViews, new[] {"dummy.txt"} } - }; - foreach (var directory in directories) - { - var directoryInfo = new DirectoryInfo(IOHelper.MapPath(directory)); - var preserve = preserves.ContainsKey(directory) ? preserves[directory] : null; - if (directoryInfo.Exists) - foreach (var x in directoryInfo.GetFiles().Where(x => preserve == null || preserve.Contains(x.Name) == false)) - x.Delete(); - } - } - - public static void CleanUmbracoSettingsConfig() - { - var currDir = new DirectoryInfo(WorkingDirectory); - - var umbracoSettingsFile = Path.Combine(currDir.Parent.Parent.FullName, "config", "umbracoSettings.config"); - if (File.Exists(umbracoSettingsFile)) - File.Delete(umbracoSettingsFile); - } - - // TODO: Move to Assertions or AssertHelper - // FIXME: obsolete the dateTimeFormat thing and replace with dateDelta - public static void AssertPropertyValuesAreEqual(object actual, object expected, string dateTimeFormat = null, Func sorter = null, string[] ignoreProperties = null) - { - const int dateDeltaMilliseconds = 500; // .5s - - var properties = expected.GetType().GetProperties(); - foreach (var property in properties) - { - // ignore properties that are attributed with EditorBrowsableState.Never - var att = property.GetCustomAttribute(false); - if (att != null && att.State == EditorBrowsableState.Never) - continue; - - // ignore explicitely ignored properties - if (ignoreProperties != null && ignoreProperties.Contains(property.Name)) - continue; - - var actualValue = property.GetValue(actual, null); - var expectedValue = property.GetValue(expected, null); - - AssertAreEqual(property, expectedValue, actualValue, sorter, dateDeltaMilliseconds); - } - } - - private static void AssertAreEqual(PropertyInfo property, object expected, object actual, Func sorter = null, int dateDeltaMilliseconds = 0) - { - if (!(expected is string) && expected is IEnumerable) - { - // sort property collection by alias, not by property ids - // on members, built-in properties don't have ids (always zero) - if (expected is PropertyCollection) - sorter = e => ((PropertyCollection) e).OrderBy(x => x.Alias); - - // compare lists - AssertListsAreEqual(property, (IEnumerable) actual, (IEnumerable) expected, sorter, dateDeltaMilliseconds); - } - else if (expected is DateTime expectedDateTime) - { - // compare date & time with delta - var actualDateTime = (DateTime) actual; - var delta = (actualDateTime - expectedDateTime).TotalMilliseconds; - Assert.IsTrue(Math.Abs(delta) <= dateDeltaMilliseconds, "Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, expected, actual); - } - else if (expected is Property expectedProperty) - { - // compare values - var actualProperty = (Property) actual; - var expectedPropertyValues = expectedProperty.Values.OrderBy(x => x.Culture).ThenBy(x => x.Segment).ToArray(); - var actualPropertyValues = actualProperty.Values.OrderBy(x => x.Culture).ThenBy(x => x.Segment).ToArray(); - if (expectedPropertyValues.Length != actualPropertyValues.Length) - Assert.Fail($"{property.DeclaringType.Name}.{property.Name}: Expected {expectedPropertyValues.Length} but got {actualPropertyValues.Length}."); - for (var i = 0; i < expectedPropertyValues.Length; i++) - { - Assert.AreEqual(expectedPropertyValues[i].EditedValue, actualPropertyValues[i].EditedValue, $"{property.DeclaringType.Name}.{property.Name}: Expected draft value \"{expectedPropertyValues[i].EditedValue}\" but got \"{actualPropertyValues[i].EditedValue}\"."); - Assert.AreEqual(expectedPropertyValues[i].PublishedValue, actualPropertyValues[i].PublishedValue, $"{property.DeclaringType.Name}.{property.Name}: Expected published value \"{expectedPropertyValues[i].EditedValue}\" but got \"{actualPropertyValues[i].EditedValue}\"."); - } - } - else if (expected is IDataEditor expectedEditor) - { - Assert.IsInstanceOf(actual); - var actualEditor = (IDataEditor) actual; - Assert.AreEqual(expectedEditor.Alias, actualEditor.Alias); - // what else shall we test? - } - else - { - // directly compare values - Assert.AreEqual(expected, actual, "Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, - expected?.ToString() ?? "", actual?.ToString() ?? ""); - } - } - - private static void AssertListsAreEqual(PropertyInfo property, IEnumerable expected, IEnumerable actual, Func sorter = null, int dateDeltaMilliseconds = 0) - { - - - if (sorter == null) - { - // this is pretty hackerific but saves us some code to write - sorter = enumerable => - { - // semi-generic way of ensuring any collection of IEntity are sorted by Ids for comparison - var entities = enumerable.OfType().ToList(); - return entities.Count > 0 ? (IEnumerable) entities.OrderBy(x => x.Id) : entities; - }; - } - - var expectedListEx = sorter(expected).Cast().ToList(); - var actualListEx = sorter(actual).Cast().ToList(); - - if (actualListEx.Count != expectedListEx.Count) - Assert.Fail("Collection {0}.{1} does not match. Expected IEnumerable containing {2} elements but was IEnumerable containing {3} elements", property.PropertyType.Name, property.Name, expectedListEx.Count, actualListEx.Count); - - for (var i = 0; i < actualListEx.Count; i++) - AssertAreEqual(property, expectedListEx[i], actualListEx[i], sorter, dateDeltaMilliseconds); - } - - public static void DeleteDirectory(string path) - { - Try(() => - { - if (Directory.Exists(path) == false) return; - foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)) - File.Delete(file); - }); - - Try(() => - { - if (Directory.Exists(path) == false) return; - Directory.Delete(path, true); - }); - } - - public static void TryAssert(Action action, int maxTries = 5, int waitMilliseconds = 200) - { - Try(action, maxTries, waitMilliseconds); - } - - public static void Try(Action action, int maxTries = 5, int waitMilliseconds = 200) - { - Try(action, maxTries, waitMilliseconds); - } - - public static void Try(Action action, int maxTries = 5, int waitMilliseconds = 200) - where T : Exception - { - var tries = 0; - while (true) - { - try - { - action(); - break; - } - catch (T) - { - if (tries++ > maxTries) - throw; - Thread.Sleep(waitMilliseconds); - } - } - } - - public static IUmbracoVersion GetUmbracoVersion() => _testHelperInternal.GetUmbracoVersion(); - - public static IServiceCollection GetRegister() => _testHelperInternal.GetRegister().AddLazySupport(); - - public static IHostingEnvironment GetHostingEnvironment() => _testHelperInternal.GetHostingEnvironment(); - - public static ILoggingConfiguration GetLoggingConfiguration(IHostingEnvironment hostingEnv) => _testHelperInternal.GetLoggingConfiguration(hostingEnv); - - public static IApplicationShutdownRegistry GetHostingEnvironmentLifetime() => _testHelperInternal.GetHostingEnvironmentLifetime(); - - public static IIpResolver GetIpResolver() => _testHelperInternal.GetIpResolver(); - - public static IRequestCache GetRequestCache() => _testHelperInternal.GetRequestCache(); - - public static IHttpContextAccessor GetHttpContextAccessor(HttpContextBase httpContextBase = null) - { - if (httpContextBase is null) - { - var httpContextMock = new Mock(); - - httpContextMock.Setup(x => x.DisposeOnPipelineCompleted(It.IsAny())) - .Returns(Mock.Of()); - - httpContextBase = httpContextMock.Object; - } - - var mock = new Mock(); - - mock.Setup(x => x.HttpContext).Returns(httpContextBase); - - return mock.Object; - } - - public static IPublishedUrlProvider GetPublishedUrlProvider() => _testHelperInternal.GetPublishedUrlProvider(); - - public static IServiceProvider CreateServiceProvider(IUmbracoBuilder builder) - { - builder.Build(); - return builder.Services.BuildServiceProvider(); - } - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs b/tests/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs deleted file mode 100644 index 1f32e739162e..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs +++ /dev/null @@ -1,327 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Common; -using System.Linq; -using System.Linq.Expressions; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; -using Moq; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Persistence.SqlCe; -using Umbraco.Cms.Tests.Common; -using Umbraco.Cms.Tests.Common.TestHelpers; -using Umbraco.Extensions; -using Umbraco.Web; - -namespace Umbraco.Tests.TestHelpers -{ - /// - /// Provides objects for tests. - /// - internal partial class TestObjects - { - /// - /// Gets a mocked IUmbracoDatabaseFactory. - /// - /// An IUmbracoDatabaseFactory. - /// A value indicating whether the factory is configured. - /// A value indicating whether the factory can connect to the database. - /// This is just a void factory that has no actual database. - public IUmbracoDatabaseFactory GetDatabaseFactoryMock(bool configured = true, bool canConnect = true) - { - var sqlSyntax = new SqlCeSyntaxProvider(Options.Create(new GlobalSettings())); - var sqlContext = Mock.Of(); - Mock.Get(sqlContext).Setup(x => x.SqlSyntax).Returns(sqlSyntax); - - var databaseFactoryMock = new Mock(); - databaseFactoryMock.Setup(x => x.Configured).Returns(configured); - databaseFactoryMock.Setup(x => x.CanConnect).Returns(canConnect); - databaseFactoryMock.Setup(x => x.SqlContext).Returns(sqlContext); - - // can create a database - but don't try to use it! - if (configured && canConnect) - databaseFactoryMock.Setup(x => x.CreateDatabase()).Returns(GetUmbracoSqlCeDatabase(Mock.Of>())); - - return databaseFactoryMock.Object; - } - - /// - /// Gets a mocked service context built with mocked services. - /// - /// A ServiceContext. - public ServiceContext GetServiceContextMock(IServiceProvider container = null) - { - // FIXME: else some tests break - figure it out - container = null; - - return ServiceContext.CreatePartial( - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container), - MockService(container)); - } - - private T MockService(IServiceProvider container = null) - where T : class - { - return container?.GetService() ?? new Mock().Object; - } - - /// - /// Gets an opened database connection that can begin a transaction. - /// - /// A DbConnection. - /// This is because NPoco wants a DbConnection, NOT an IDbConnection, - /// and DbConnection is hard to mock so we create our own class here. - public DbConnection GetDbConnection() - { - return new MockDbConnection(); - } - - /// - /// Gets an Umbraco context. - /// - /// An Umbraco context. - /// This should be the minimum Umbraco context. - public IUmbracoContext GetUmbracoContextMock(IUmbracoContextAccessor accessor = null) - { - - var publishedSnapshotMock = new Mock(); - publishedSnapshotMock.Setup(x => x.Members).Returns(Mock.Of()); - var publishedSnapshot = publishedSnapshotMock.Object; - var publishedSnapshotServiceMock = new Mock(); - publishedSnapshotServiceMock.Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(publishedSnapshot); - var publishedSnapshotService = publishedSnapshotServiceMock.Object; - - var globalSettings = GetGlobalSettings(); - - if (accessor == null) accessor = new TestUmbracoContextAccessor(); - - var httpContextAccessor = TestHelper.GetHttpContextAccessor(); - - var umbracoContextFactory = new UmbracoContextFactory( - accessor, - publishedSnapshotService, - new TestVariationContextAccessor(), - new TestDefaultCultureAccessor(), - globalSettings, - Mock.Of(), - TestHelper.GetHostingEnvironment(), - TestHelper.UriUtility, - httpContextAccessor, - new AspNetCookieManager(httpContextAccessor)); - - return umbracoContextFactory.EnsureUmbracoContext().UmbracoContext; - } - - public GlobalSettings GetGlobalSettings() - { - return new GlobalSettings(); - } - public FileSystems GetFileSystemsMock() - { - var fileSystems = FileSystemsCreator.CreateTestFileSystems( - NullLoggerFactory.Instance, - Mock.Of(), - Mock.Of>(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of() - ); - - return fileSystems; - } - - #region Inner classes - - private class MockDbConnection : DbConnection - { - protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) - { - return Mock.Of(); // enough here - } - - public override void Close() - { - throw new NotImplementedException(); - } - - public override void ChangeDatabase(string databaseName) - { - throw new NotImplementedException(); - } - - public override void Open() - { - throw new NotImplementedException(); - } - - public override string ConnectionString { get; set; } - - protected override DbCommand CreateDbCommand() - { - throw new NotImplementedException(); - } - - public override string Database { get; } - public override string DataSource { get; } - public override string ServerVersion { get; } - public override ConnectionState State => ConnectionState.Open; // else NPoco reopens - } - - public class TestDataTypeService : IDataTypeService - { - public TestDataTypeService() - { - DataTypes = new Dictionary(); - } - - public TestDataTypeService(params IDataType[] dataTypes) - { - DataTypes = dataTypes.ToDictionary(x => x.Id, x => x); - } - - public TestDataTypeService(IEnumerable dataTypes) - { - DataTypes = dataTypes.ToDictionary(x => x.Id, x => x); - } - - public Dictionary DataTypes { get; } - - public Attempt> CreateContainer(int parentId, string name, int userId = -1) - { - throw new NotImplementedException(); - } - - public Attempt SaveContainer(EntityContainer container, int userId = -1) - { - throw new NotImplementedException(); - } - - public EntityContainer GetContainer(int containerId) - { - throw new NotImplementedException(); - } - - public EntityContainer GetContainer(Guid containerId) - { - throw new NotImplementedException(); - } - - public IEnumerable GetContainers(string folderName, int level) - { - throw new NotImplementedException(); - } - - public IEnumerable GetContainers(IDataType dataType) - { - throw new NotImplementedException(); - } - - public IEnumerable GetContainers(int[] containerIds) - { - throw new NotImplementedException(); - } - - public Attempt DeleteContainer(int containerId, int userId = -1) - { - throw new NotImplementedException(); - } - - public Attempt> RenameContainer(int id, string name, int userId = -1) - { - throw new NotImplementedException(); - } - - public IDataType GetDataType(string name) - { - throw new NotImplementedException(); - } - - public IDataType GetDataType(int id) - { - DataTypes.TryGetValue(id, out var dataType); - return dataType; - } - - public IDataType GetDataType(Guid id) - { - throw new NotImplementedException(); - } - - public IEnumerable GetAll(params int[] ids) - { - if (ids.Length == 0) return DataTypes.Values; - return ids.Select(x => DataTypes.TryGetValue(x, out var dataType) ? dataType : null).WhereNotNull(); - } - - public void Save(IDataType dataType, int userId = -1) - { - throw new NotImplementedException(); - } - - public void Save(IEnumerable dataTypeDefinitions, int userId = -1) - { - throw new NotImplementedException(); - } - - public void Save(IEnumerable dataTypeDefinitions, int userId, bool raiseEvents) - { - throw new NotImplementedException(); - } - - public void Delete(IDataType dataType, int userId = -1) - { - throw new NotImplementedException(); - } - - public IEnumerable GetByEditorAlias(string propertyEditorAlias) - { - throw new NotImplementedException(); - } - - public Attempt> Move(IDataType toMove, int parentId) - { - throw new NotImplementedException(); - } - - public IReadOnlyDictionary> GetReferences(int id) - { - throw new NotImplementedException(); - } - } - - #endregion - - - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/TestObjects.cs b/tests/Umbraco.Tests/TestHelpers/TestObjects.cs deleted file mode 100644 index 6f7fcfe2ddec..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/TestObjects.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Moq; -using NPoco; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Configuration; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Infrastructure.Migrations.Install; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Infrastructure.Persistence.Mappers; -using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; -using Umbraco.Cms.Persistence.SqlCe; -using Umbraco.Web.Composing; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Tests.TestHelpers -{ - /// - /// Provides objects for tests. - /// - internal partial class TestObjects - { - - public TestObjects() - { - } - - /// - /// Gets an UmbracoDatabase. - /// - /// A logger. - /// An UmbracoDatabase. - /// This is just a void database that has no actual database but pretends to have an open connection - /// that can begin a transaction. - public UmbracoDatabase GetUmbracoSqlCeDatabase(ILogger logger) - { - var syntax = new SqlCeSyntaxProvider(Options.Create(new GlobalSettings())); - var connection = GetDbConnection(); - var sqlContext = new SqlContext(syntax, DatabaseType.SQLCe, Mock.Of()); - return new UmbracoDatabase(connection, sqlContext, logger, TestHelper.BulkSqlInsertProvider); - } - - /// - /// Gets an UmbracoDatabase. - /// - /// A logger. - /// An UmbracoDatabase. - /// This is just a void database that has no actual database but pretends to have an open connection - /// that can begin a transaction. - public UmbracoDatabase GetUmbracoSqlServerDatabase(ILogger logger) - { - var syntax = new SqlServerSyntaxProvider(Options.Create(new GlobalSettings())); // do NOT try to get the server's version! - var connection = GetDbConnection(); - var sqlContext = new SqlContext(syntax, DatabaseType.SqlServer2008, Mock.Of()); - return new UmbracoDatabase(connection, sqlContext, logger, TestHelper.BulkSqlInsertProvider); - } - - public IScopeProvider GetScopeProvider(ILoggerFactory loggerFactory, FileSystems fileSystems = null, IUmbracoDatabaseFactory databaseFactory = null) - { - var globalSettings = Options.Create(new GlobalSettings()); - var connectionString = ConfigurationManager.ConnectionStrings[Constants.System.UmbracoConnectionName].ConnectionString; - var connectionStrings = Options.Create(new ConnectionStrings { UmbracoConnectionString = new ConfigConnectionString(Constants.System.UmbracoConnectionName, connectionString) }); - var coreDebugSettings = new CoreDebugSettings(); - - if (databaseFactory == null) - { - // var mappersBuilder = new MapperCollectionBuilder(Current.Container); // FIXME: - // mappersBuilder.AddCore(); - // var mappers = mappersBuilder.CreateCollection(); - var mappers = Current.Factory.GetRequiredService(); - databaseFactory = new UmbracoDatabaseFactory( - loggerFactory.CreateLogger(), - loggerFactory, - globalSettings, - connectionStrings, - new Lazy(() => mappers), - TestHelper.DbProviderFactoryCreator, - new DatabaseSchemaCreatorFactory(Mock.Of>(),loggerFactory, new UmbracoVersion(), Mock.Of())); - } - - fileSystems ??= new FileSystems(loggerFactory, TestHelper.IOHelper, globalSettings, TestHelper.GetHostingEnvironment()); - var coreDebug = TestHelper.CoreDebugSettings; - var mediaFileManager = Mock.Of(); - var eventAggregator = Mock.Of(); - return new ScopeProvider(databaseFactory, fileSystems, Options.Create(coreDebugSettings), mediaFileManager, loggerFactory.CreateLogger(), loggerFactory, NoAppCache.Instance, eventAggregator); - } - - } -} diff --git a/tests/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/tests/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs deleted file mode 100644 index 9c0651037067..000000000000 --- a/tests/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ /dev/null @@ -1,429 +0,0 @@ -using System; -using System.Configuration; -using System.Data.SqlServerCe; -using System.IO; -using System.Threading; -using System.Web.Routing; -using System.Xml; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Persistence.Repositories; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure.Migrations.Install; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Infrastructure.Persistence.Mappers; -using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; -using Umbraco.Cms.Persistence.SqlCe; -using Umbraco.Cms.Tests.Common; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Extensions; -using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.Testing; -using Umbraco.Web; -using Umbraco.Web.Composing; -using Umbraco.Web.WebApi; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Tests.TestHelpers -{ - /// - /// Provides a base class for all Umbraco tests that require a database. - /// - /// - /// Can provide a SqlCE database populated with the Umbraco schema. The database should - /// be accessed through the UmbracoDatabaseFactory. - /// Provides an Umbraco context and Xml content. - /// fixme what else? - /// - [UmbracoTest(WithApplication = true)] - public abstract class TestWithDatabaseBase : UmbracoTestBase - { - private string _databasePath; - private static byte[] _databaseBytes; - - protected PublishedContentTypeCache ContentTypesCache { get; private set; } - - protected override ISqlSyntaxProvider SqlSyntax => GetSyntaxProvider(); - protected IVariationContextAccessor VariationContextAccessor => new TestVariationContextAccessor(); - - internal ScopeProvider ScopeProvider => Current.ScopeProvider as ScopeProvider; - internal IUmbracoDatabaseFactory UmbracoDatabaseFactory => Factory.GetRequiredService(); - internal IDataValueEditorFactory DataValueEditorFactory => Factory.GetRequiredService(); - - protected ISqlContext SqlContext => Factory.GetRequiredService(); - - public override void SetUp() - { - // Ensure the data directory is set before continuing - var path = TestHelper.WorkingDirectory; - AppDomain.CurrentDomain.SetData("DataDirectory", path); - - base.SetUp(); - } - - protected override void Compose() - { - base.Compose(); - - Builder.Services.AddTransient(); - Builder.Services.AddTransient(factory => PublishedSnapshotService); - Builder.Services.AddTransient(factory => DefaultCultureAccessor); - - Builder.WithCollectionBuilder() - .Clear() - .Add(() => Builder.TypeLoader.GetDataEditors()); - - Builder.WithCollectionBuilder() - .Add(Builder.TypeLoader.GetUmbracoApiControllers()); - - Builder.Services.AddUnique(f => - { - if (Options.Database == UmbracoTestOptions.Database.None) - return TestObjects.GetDatabaseFactoryMock(); - - var lazyMappers = new Lazy(f.GetRequiredService); - var factory = new UmbracoDatabaseFactory(f.GetRequiredService>(), f.GetRequiredService(), GetDbConnectionString(), GetDbProviderName(), lazyMappers, TestHelper.DbProviderFactoryCreator, f.GetRequiredService()); - return factory; - }); - } - - [OneTimeTearDown] - public void FixtureTearDown() - { - RemoveDatabaseFile(); - } - - public override void TearDown() - { - var profilingLogger = Factory.GetService(); - var timer = profilingLogger?.TraceDuration("teardown"); // FIXME: move that one up - try - { - // FIXME: should we first kill all scopes? - if (Options.Database == UmbracoTestOptions.Database.NewSchemaPerTest) - RemoveDatabaseFile(); - - AppDomain.CurrentDomain.SetData("DataDirectory", null); - - // make sure we dispose of the service to unbind events - PublishedSnapshotService?.Dispose(); - PublishedSnapshotService = null; - } - finally - { - timer?.Dispose(); - } - - base.TearDown(); - } - - private void CreateAndInitializeDatabase() - { - using (ProfilingLogger.TraceDuration("Create database.")) - { - CreateSqlCeDatabase(); // TODO: faster! - } - - using (ProfilingLogger.TraceDuration("Initialize database.")) - { - InitializeDatabase(); // TODO: faster! - } - } - - protected virtual ISqlSyntaxProvider GetSyntaxProvider() - { - return new SqlCeSyntaxProvider(Microsoft.Extensions.Options.Options.Create(new GlobalSettings())); - } - - protected virtual string GetDbProviderName() - { - return Constants.DbProviderNames.SqlCe; - } - - protected virtual string GetDbConnectionString() - { - return @"DataSource=|DataDirectory|UmbracoNPocoTests.sdf;Flush Interval=1;"; - } - - - - /// - /// Creates the SqlCe database if required - /// - protected virtual void CreateSqlCeDatabase() - { - if (Options.Database == UmbracoTestOptions.Database.None) - return; - - var path = TestHelper.WorkingDirectory; - - //Get the connectionstring settings from config - var settings = ConfigurationManager.ConnectionStrings[Constants.System.UmbracoConnectionName]; - ConfigurationManager.AppSettings.Set( - Constants.System.UmbracoConnectionName, - GetDbConnectionString()); - - _databasePath = string.Concat(path, "\\UmbracoNPocoTests.sdf"); - - //create a new database file if - // - is the first test in the session - // - the database file doesn't exist - // - NewDbFileAndSchemaPerTest - // - _isFirstTestInFixture + DbInitBehavior.NewDbFileAndSchemaPerFixture - - //if this is the first test in the session, always ensure a new db file is created - if (FirstTestInSession - || File.Exists(_databasePath) == false - || Options.Database == UmbracoTestOptions.Database.NewSchemaPerTest - || Options.Database == UmbracoTestOptions.Database.NewEmptyPerTest - || (FirstTestInFixture && Options.Database == UmbracoTestOptions.Database.NewSchemaPerFixture)) - { - using (ProfilingLogger.TraceDuration("Remove database file")) - { - RemoveDatabaseFile(null, ex => - { - //if this doesn't work we have to make sure everything is reset! otherwise - // well run into issues because we've already set some things up - TearDown(); - throw ex; - }); - } - - //Create the Sql CE database - using (ProfilingLogger.TraceDuration("Create database file")) - { - if (Options.Database != UmbracoTestOptions.Database.NewEmptyPerTest && _databaseBytes != null) - { - File.WriteAllBytes(_databasePath, _databaseBytes); - } - else - { - using (var engine = new SqlCeEngine(settings.ConnectionString)) - { - engine.CreateDatabase(); - } - } - } - - } - } - - protected IDefaultCultureAccessor DefaultCultureAccessor { get; set; } - - protected IPublishedSnapshotService PublishedSnapshotService { get; set; } - - protected override void Initialize() // FIXME: should NOT be here! - { - base.Initialize(); - - DefaultCultureAccessor = new TestDefaultCultureAccessor(); - - CreateAndInitializeDatabase(); - - // ensure we have a PublishedSnapshotService - if (PublishedSnapshotService == null) - { - PublishedSnapshotService = CreatePublishedSnapshotService(); - } - } - - protected virtual IPublishedSnapshotService CreatePublishedSnapshotService(GlobalSettings globalSettings = null) - { - var cache = NoAppCache.Instance; - - ContentTypesCache ??= new PublishedContentTypeCache( - Factory.GetRequiredService(), - Factory.GetRequiredService(), - Factory.GetRequiredService(), - Factory.GetRequiredService(), - Factory.GetRequiredService>()); - - // testing=true so XmlStore will not use the file nor the database - - var publishedSnapshotAccessor = new UmbracoContextPublishedSnapshotAccessor(Umbraco.Web.Composing.Current.UmbracoContextAccessor); - var variationContextAccessor = new TestVariationContextAccessor(); - var service = new XmlPublishedSnapshotService( - ServiceContext, - Factory.GetRequiredService(), - ScopeProvider, - cache, publishedSnapshotAccessor, variationContextAccessor, - Factory.GetRequiredService(), - Factory.GetRequiredService(), Factory.GetRequiredService(), Factory.GetRequiredService(), - DefaultCultureAccessor, - Factory.GetRequiredService(), - globalSettings ?? TestObjects.GetGlobalSettings(), - HostingEnvironment, - HostingLifetime, - ShortStringHelper, - Factory.GetRequiredService(), - ContentTypesCache, - null, true, Options.PublishedRepositoryEvents); - - // initialize PublishedCacheService content with an Xml source - service.XmlStore.GetXmlDocument = () => - { - var doc = new XmlDocument(); - doc.LoadXml(GetXmlContent(0)); - return doc; - }; - - return service; - } - - /// - /// Creates the tables and data for the database - /// - protected virtual void InitializeDatabase() - { - if (Options.Database == UmbracoTestOptions.Database.None || Options.Database == UmbracoTestOptions.Database.NewEmptyPerTest) - return; - - //create the schema and load default data if: - // - is the first test in the session - // - NewDbFileAndSchemaPerTest - // - _isFirstTestInFixture + DbInitBehavior.NewDbFileAndSchemaPerFixture - - if (_databaseBytes == null && - (FirstTestInSession - || Options.Database == UmbracoTestOptions.Database.NewSchemaPerTest - || FirstTestInFixture && Options.Database == UmbracoTestOptions.Database.NewSchemaPerFixture)) - { - using (var scope = ScopeProvider.CreateScope()) - { - var schemaHelper = new DatabaseSchemaCreator(scope.Database, LoggerFactory.CreateLogger(), LoggerFactory, UmbracoVersion, Mock.Of()); - //Create the umbraco database and its base data - schemaHelper.InitializeDatabaseSchema(); - - //Special case, we need to create the xml cache tables manually since they are not part of the default - //setup. - //TODO: Remove this when we update all tests to use nucache - schemaHelper.CreateTable(); - schemaHelper.CreateTable(); - - scope.Complete(); - } - - _databaseBytes = File.ReadAllBytes(_databasePath); - } - } - - // FIXME: is this needed? - private void CloseDbConnections(IUmbracoDatabase database) - { - //Ensure that any database connections from a previous test is disposed. - //This is really just double safety as its also done in the TearDown. - database?.Dispose(); - //SqlCeContextGuardian.CloseBackgroundConnection(); - } - - private void RemoveDatabaseFile(IUmbracoDatabase database, Action onFail = null) - { - if (database != null) CloseDbConnections(database); - RemoveDatabaseFile(onFail); - } - - private void RemoveDatabaseFile(Action onFail = null) - { - var path = TestHelper.WorkingDirectory; - try - { - var filePath = string.Concat(path, "\\UmbracoNPocoTests.sdf"); - if (File.Exists(filePath)) - File.Delete(filePath); - } - catch (Exception ex) - { - LoggerFactory.CreateLogger().LogError(ex, "Could not remove the old database file"); - - // swallow this exception - that's because a sub class might require further teardown logic - onFail?.Invoke(ex); - } - } - - protected IUmbracoContextAccessor GetUmbracoContextAccessor(IUmbracoContext ctx) => new TestUmbracoContextAccessor(ctx); - - protected IUmbracoContext GetUmbracoContext(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, GlobalSettings globalSettings = null, IPublishedSnapshotService snapshotService = null) - { - // ensure we have a PublishedCachesService - var service = snapshotService ?? PublishedSnapshotService as XmlPublishedSnapshotService; - if (service == null) - throw new Exception("Not a proper XmlPublishedCache.PublishedCachesService."); - - if (service is XmlPublishedSnapshotService) - { - // re-initialize PublishedCacheService content with an Xml source with proper template id - ((XmlPublishedSnapshotService)service).XmlStore.GetXmlDocument = () => - { - var doc = new XmlDocument(); - doc.LoadXml(GetXmlContent(templateId)); - return doc; - }; - } - - var httpContext = GetHttpContextFactory(url, routeData).HttpContext; - var httpContextAccessor = TestHelper.GetHttpContextAccessor(httpContext); - var umbracoContext = new UmbracoContext( - httpContextAccessor, - service, - Mock.Of(), - globalSettings ?? new GlobalSettings(), - HostingEnvironment, - new TestVariationContextAccessor(), - UriUtility, - new AspNetCookieManager(httpContextAccessor)); - - if (setSingleton) - Umbraco.Web.Composing.Current.UmbracoContextAccessor.UmbracoContext = umbracoContext; - - return umbracoContext; - } - - protected virtual string GetXmlContent(int templateId) - { - return @" - - - - -]> - - - - - 1 - - This is some content]]> - - - - - - - - - - - - - - - - -"; - } - } -} diff --git a/tests/Umbraco.Tests/Testing/Objects/Accessors/NoHttpContextAccessor.cs b/tests/Umbraco.Tests/Testing/Objects/Accessors/NoHttpContextAccessor.cs deleted file mode 100644 index e34ff7bb458f..000000000000 --- a/tests/Umbraco.Tests/Testing/Objects/Accessors/NoHttpContextAccessor.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Web; -using Umbraco.Web; - -namespace Umbraco.Tests.Testing.Objects.Accessors -{ - public class NoHttpContextAccessor : IHttpContextAccessor - { - public HttpContextBase HttpContext { get; set; } = null; - } -} diff --git a/tests/Umbraco.Tests/Testing/Objects/TestDataSource.cs b/tests/Umbraco.Tests/Testing/Objects/TestDataSource.cs deleted file mode 100644 index 97419ebe269e..000000000000 --- a/tests/Umbraco.Tests/Testing/Objects/TestDataSource.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Infrastructure.PublishedCache; -using Umbraco.Cms.Infrastructure.PublishedCache.Persistence; - -namespace Umbraco.Tests.Testing.Objects -{ - internal class TestDataSource : INuCacheContentService - { - private IPublishedModelFactory PublishedModelFactory { get; } = new NoopPublishedModelFactory(); - - public TestDataSource(params ContentNodeKit[] kits) - : this((IEnumerable) kits) - { } - - public TestDataSource(IEnumerable kits) => Kits = kits.ToDictionary(x => x.Node.Id, x => x); - - public Dictionary Kits { get; } - - // note: it is important to clone the returned kits, as the inner - // ContentNode is directly reused and modified by the snapshot service - public ContentNodeKit GetContentSource(int id) - => Kits.TryGetValue(id, out ContentNodeKit kit) ? kit.Clone(PublishedModelFactory) : default; - - public IEnumerable GetAllContentSources() - => Kits.Values - .OrderBy(x => x.Node.Level) - .ThenBy(x => x.Node.ParentContentId) - .ThenBy(x => x.Node.SortOrder) - .Select(x => x.Clone(PublishedModelFactory)); - - public IEnumerable GetBranchContentSources(int id) - => Kits.Values - .Where(x => x.Node.Path.EndsWith("," + id) || x.Node.Path.Contains("," + id + ",")) - .OrderBy(x => x.Node.Level) - .ThenBy(x => x.Node.ParentContentId) - .ThenBy(x => x.Node.SortOrder) - .Select(x => x.Clone(PublishedModelFactory)); - - public IEnumerable GetTypeContentSources(IEnumerable ids) - => Kits.Values - .Where(x => ids.Contains(x.ContentTypeId)) - .OrderBy(x => x.Node.Level) - .ThenBy(x => x.Node.ParentContentId) - .ThenBy(x => x.Node.SortOrder) - .Select(x => x.Clone(PublishedModelFactory)); - - public ContentNodeKit GetMediaSource(int id) => default; - - public IEnumerable GetAllMediaSources() => Enumerable.Empty(); - - public IEnumerable GetBranchMediaSources(int id) => Enumerable.Empty(); - - public IEnumerable GetTypeMediaSources(IEnumerable ids) => Enumerable.Empty(); - public void DeleteContentItem(IContentBase item) => throw new NotImplementedException(); - public void DeleteContentItems(IEnumerable items) => throw new NotImplementedException(); - public void RefreshContent(IContent content) => throw new NotImplementedException(); - public void RefreshEntity(IContentBase content) => throw new NotImplementedException(); - public bool VerifyContentDbCache() => throw new NotImplementedException(); - public bool VerifyMediaDbCache() => throw new NotImplementedException(); - public bool VerifyMemberDbCache() => throw new NotImplementedException(); - public void Rebuild(int groupSize = 5000, IReadOnlyCollection contentTypeIds = null, IReadOnlyCollection mediaTypeIds = null, IReadOnlyCollection memberTypeIds = null) => throw new NotImplementedException(); - } -} diff --git a/tests/Umbraco.Tests/Testing/UmbracoTestBase.cs b/tests/Umbraco.Tests/Testing/UmbracoTestBase.cs deleted file mode 100644 index 243e92ad537a..000000000000 --- a/tests/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ /dev/null @@ -1,585 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Web.Routing; -using System.Xml.Linq; -using Examine; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; -using Moq; -using NUnit.Framework; -using Serilog; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Actions; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Composing; -using Umbraco.Cms.Core.Configuration; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.ContentApps; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Dictionary; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.Install; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.IO.MediaPathSchemes; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Mail; -using Umbraco.Cms.Core.Manifest; -using Umbraco.Cms.Core.Mapping; -using Umbraco.Cms.Core.Media; -using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Core.Net; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Sections; -using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Core.Serialization; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Services.Implement; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Core.Templates; -using Umbraco.Cms.Core.Trees; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure; -using Umbraco.Cms.Infrastructure.DependencyInjection; -using Umbraco.Cms.Infrastructure.Media; -using Umbraco.Cms.Infrastructure.Migrations.Install; -using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Infrastructure.Persistence.Mappers; -using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; -using Umbraco.Cms.Infrastructure.Serialization; -using Umbraco.Cms.Tests.Common; -using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Extensions; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Stubs; -using Umbraco.Web; -using Umbraco.Web.Composing; -using Umbraco.Web.Hosting; -using Umbraco.Web.Security; -using ILogger = Microsoft.Extensions.Logging.ILogger; - -namespace Umbraco.Tests.Testing -{ - /// - /// Provides the top-level base class for all Umbraco integration tests. - /// - /// - /// True unit tests do not need to inherit from this class, but most of Umbraco tests - /// are not true unit tests but integration tests requiring services, databases, etc. This class - /// provides all the necessary environment, through DI. Yes, DI is bad in tests - unit tests. - /// But it is OK in integration tests. - /// - public abstract class UmbracoTestBase - { - // this class - // ensures that Current is properly resetted - // ensures that a service container is properly initialized and disposed - // compose the required dependencies according to test options (UmbracoTestAttribute) - // - // everything is virtual (because, why not?) - // starting a test runs like this: - // - SetUp() // when overriding, call base.SetUp() *first* then setup your own stuff - // --- Compose() // when overriding, call base.Commpose() *first* then compose your own stuff - // --- Initialize() // same - // - test runs - // - TearDown() // when overriding, clear you own stuff *then* call base.TearDown() - // - // about attributes - // - // this class defines the SetUp and TearDown methods, with proper attributes, and - // these attributes are *inherited* so classes inheriting from this class should *not* - // add the attributes to SetUp nor TearDown again - // - // this class is *not* marked with the TestFeature attribute because it is *not* a - // test feature, and no test "base" class should be. only actual test feature classes - // should be marked with that attribute. - - protected IUmbracoBuilder Builder { get; private set; } - - protected IServiceProvider Factory { get; private set; } - - protected UmbracoTestAttribute Options { get; private set; } - - protected static bool FirstTestInSession { get; set; } = true; - - protected bool FirstTestInFixture { get; set; } = true; - - internal TestObjects TestObjects { get; private set; } - - private static TypeLoader _commonTypeLoader; - - private TypeLoader _featureTypeLoader; - - #region Accessors - protected ServiceContext ServiceContext => Factory.GetRequiredService(); - - protected ILoggerFactory LoggerFactory => Factory.GetRequiredService(); - - protected IJsonSerializer JsonNetSerializer { get; } = new JsonNetSerializer(); - - protected IIOHelper IOHelper { get; private set; } - protected UriUtility UriUtility => new UriUtility(HostingEnvironment); - protected IPublishedUrlProvider PublishedUrlProvider => Factory.GetRequiredService(); - protected IDataTypeService DataTypeService => Factory.GetRequiredService(); - protected IPasswordHasher PasswordHasher => Factory.GetRequiredService(); - protected Lazy PropertyEditorCollection => new Lazy(() => Factory.GetRequiredService()); - protected ILocalizationService LocalizationService => Factory.GetRequiredService(); - protected ILocalizedTextService LocalizedTextService { get; private set; } - protected IShortStringHelper ShortStringHelper => Factory?.GetRequiredService() ?? TestHelper.ShortStringHelper; - protected IImageUrlGenerator ImageUrlGenerator => Factory.GetRequiredService(); - protected UploadAutoFillProperties UploadAutoFillProperties => Factory.GetRequiredService(); - protected IUmbracoVersion UmbracoVersion { get; private set; } - - protected ITypeFinder TypeFinder { get; private set; } - - protected IProfiler Profiler => Factory.GetRequiredService(); - - protected virtual IProfilingLogger ProfilingLogger => Factory.GetRequiredService(); - - protected IHostingEnvironment HostingEnvironment { get; } = new AspNetHostingEnvironment(Microsoft.Extensions.Options.Options.Create(new HostingSettings())); - protected IApplicationShutdownRegistry HostingLifetime { get; } = new AspNetApplicationShutdownRegistry(); - protected IIpResolver IpResolver => Factory.GetRequiredService(); - protected IBackOfficeInfo BackOfficeInfo => Factory.GetRequiredService(); - protected AppCaches AppCaches => Factory.GetRequiredService(); - - protected virtual ISqlSyntaxProvider SqlSyntax => Factory.GetRequiredService(); - - protected IMapperCollection Mappers => Factory.GetRequiredService(); - - protected IUmbracoMapper Mapper => Factory.GetRequiredService(); - protected IHttpContextAccessor HttpContextAccessor => Factory.GetRequiredService(); - protected IContentService ContentService => Factory.GetRequiredService(); - protected IRuntimeState RuntimeState => MockRuntimeState(RuntimeLevel.Run); - private ILoggerFactory _loggerFactory; - - protected static IRuntimeState MockRuntimeState(RuntimeLevel level) - { - var runtimeState = Mock.Of(); - Mock.Get(runtimeState).Setup(x => x.Level).Returns(level); - return runtimeState; - } - #endregion - - #region Setup - - [SetUp] - public virtual void SetUp() - { - // should not need this if all other tests were clean - // but hey, never know, better avoid garbage-in - Reset(); - - // get/merge the attributes marking the method and/or the classes - Options = TestOptionAttributeBase.GetTestOptions(); - - // FIXME: align to runtimes & components - don't redo everything here !!!! Yes this is getting painful - - var loggerFactory = GetLoggerFactory(Options.Logger); - _loggerFactory = loggerFactory; - var profiler = new LogProfiler(loggerFactory.CreateLogger()); - var msLogger = loggerFactory.CreateLogger("msLogger"); - var proflogger = new ProfilingLogger(loggerFactory.CreateLogger(), profiler); - IOHelper = TestHelper.IOHelper; - - TypeFinder = new TypeFinder(loggerFactory.CreateLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly, loggerFactory), new VaryingRuntimeHash()); - var appCaches = GetAppCaches(); - var globalSettings = new GlobalSettings(); - var settings = new WebRoutingSettings(); - - IBackOfficeInfo backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, IOHelper, loggerFactory.CreateLogger(), Microsoft.Extensions.Options.Options.Create(settings)); - IIpResolver ipResolver = new AspNetIpResolver(); - UmbracoVersion = new UmbracoVersion(); - - - LocalizedTextService = new LocalizedTextService(new Dictionary>(), loggerFactory.CreateLogger()); - var typeLoader = GetTypeLoader(IOHelper, TypeFinder, appCaches.RuntimeCache, HostingEnvironment, loggerFactory.CreateLogger(), proflogger, Options.TypeLoader); - - var services = TestHelper.GetRegister(); - - Builder = new UmbracoBuilder(services, Mock.Of(), typeLoader); - - //TestHelper.GetConfigs().RegisterWith(register); - services.AddUnique(typeof(ILoggerFactory), loggerFactory); - services.AddTransient(typeof(ILogger<>), typeof(Logger<>)); - services.AddSingleton(msLogger); - services.AddUnique(IOHelper); - services.AddUnique(UriUtility); - services.AddUnique(UmbracoVersion); - services.AddUnique(TypeFinder); - services.AddUnique(LocalizedTextService); - services.AddUnique(typeLoader); - services.AddUnique(profiler); - services.AddUnique(proflogger); - services.AddUnique(appCaches); - services.AddUnique(HostingEnvironment); - services.AddUnique(backOfficeInfo); - services.AddUnique(ipResolver); - services.AddUnique(); - services.AddUnique(TestHelper.ShortStringHelper); - //services.AddUnique(); - - - var memberService = Mock.Of(); - var memberTypeService = Mock.Of(); - - TestObjects = new TestObjects(); - Compose(); - Current.Factory = Factory = TestHelper.CreateServiceProvider(Builder); - Initialize(); - } - - protected virtual void Compose() - { - ComposeMapper(Options.Mapper); - ComposeDatabase(Options.Database); - ComposeApplication(Options.WithApplication); - - // etc - ComposeWeb(); - ComposeMisc(); - - // not sure really - Compose(Builder); - } - - protected virtual void Compose(IUmbracoBuilder builder) - { } - - protected virtual void Initialize() - { - InitializeApplication(Options.WithApplication); - } - - #endregion - - #region Compose - - protected virtual ILoggerFactory GetLoggerFactory(UmbracoTestOptions.Logger option) - { - ILoggerFactory factory; - - switch (option) - { - case UmbracoTestOptions.Logger.Mock: - factory = NullLoggerFactory.Instance; - break; - case UmbracoTestOptions.Logger.Serilog: - factory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddSerilog(); }); - break; - case UmbracoTestOptions.Logger.Console: - factory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddConsole(); }); - break; - default: - throw new NotSupportedException($"Logger option {option} is not supported."); - } - - return factory; - } - - protected virtual AppCaches GetAppCaches() - { - return AppCaches.Disabled; - } - - protected virtual void ComposeWeb() - { - // imported from TestWithSettingsBase - // which was inherited by TestWithApplicationBase so pretty much used everywhere - Current.UmbracoContextAccessor = new TestUmbracoContextAccessor(); - - // web - Builder.Services.AddUnique(Current.UmbracoContextAccessor); - Builder.Services.AddUnique(Mock.Of()); - Builder.Services.AddUnique(); - Builder.WithCollectionBuilder(); - - - Builder.DataValueReferenceFactories(); - - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - Builder.SetCultureDictionaryFactory(); - Builder.Services.AddSingleton(f => f.GetRequiredService().CreateDictionary()); - // register back office sections in the order we want them rendered - Builder.WithCollectionBuilder().Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); - Builder.Services.AddUnique(); - - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - - var webRoutingSettings = new WebRoutingSettings(); - Builder.Services.AddUnique(factory => - new UrlProvider( - factory.GetRequiredService(), - Microsoft.Extensions.Options.Options.Create(webRoutingSettings), - new UrlProviderCollection(Enumerable.Empty()), - new MediaUrlProviderCollection(Enumerable.Empty()), - factory.GetRequiredService())); - - - - } - - protected virtual void ComposeMisc() - { - // what else? - var runtimeStateMock = new Mock(); - runtimeStateMock.Setup(x => x.Level).Returns(RuntimeLevel.Run); - Builder.Services.AddUnique(f => runtimeStateMock.Object); - Builder.Services.AddTransient(_ => Mock.Of()); - Builder.Services.AddTransient(); - - // ah... - Builder.WithCollectionBuilder(); - Builder.WithCollectionBuilder(); - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - - Builder.Services.AddUnique(); - - // register empty content apps collection - Builder.WithCollectionBuilder(); - - // manifest - Builder.ManifestValueValidators(); - Builder.ManifestFilters(); - Builder.MediaUrlGenerators() - .Add() - .Add(); - - } - - protected virtual void ComposeMapper(bool configure) - { - if (configure == false) return; - - Builder - .AddCoreMappingProfiles(); - } - - protected virtual TypeLoader GetTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IHostingEnvironment hostingEnvironment, ILogger logger, IProfilingLogger profilingLogger, UmbracoTestOptions.TypeLoader option) - { - switch (option) - { - case UmbracoTestOptions.TypeLoader.Default: - return _commonTypeLoader ?? (_commonTypeLoader = CreateCommonTypeLoader(typeFinder, runtimeCache, logger, profilingLogger, hostingEnvironment)); - case UmbracoTestOptions.TypeLoader.PerFixture: - return _featureTypeLoader ?? (_featureTypeLoader = CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, profilingLogger, hostingEnvironment)); - case UmbracoTestOptions.TypeLoader.PerTest: - return CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, profilingLogger, hostingEnvironment); - default: - throw new ArgumentOutOfRangeException(nameof(option)); - } - } - - protected virtual TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, ILogger logger, IProfilingLogger profilingLogger, IHostingEnvironment hostingEnvironment) - { - return CreateCommonTypeLoader(typeFinder, runtimeCache, logger, profilingLogger, hostingEnvironment); - } - - // common to all tests = cannot be overriden - private static TypeLoader CreateCommonTypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, ILogger logger, IProfilingLogger profilingLogger, IHostingEnvironment hostingEnvironment) - { - return new TypeLoader(typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, profilingLogger, false, new[] - { - Assembly.Load("Umbraco.Core"), - Assembly.Load("Umbraco.Web"), - Assembly.Load("Umbraco.Tests"), - Assembly.Load("Umbraco.Infrastructure"), - }); - } - - protected virtual void ComposeDatabase(UmbracoTestOptions.Database option) - { - if (option == UmbracoTestOptions.Database.None) return; - - // create the file - // create the schema - } - - protected virtual void ComposeSettings() - { - var contentSettings = new ContentSettings(); - var coreDebugSettings = new CoreDebugSettings(); - var globalSettings = new GlobalSettings(); - var nuCacheSettings = new NuCacheSettings(); - var requestHandlerSettings = new RequestHandlerSettings(); - var userPasswordConfigurationSettings = new UserPasswordConfigurationSettings(); - var webRoutingSettings = new WebRoutingSettings(); - - Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(contentSettings)); - Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(coreDebugSettings)); - Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(globalSettings)); - Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); - Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(requestHandlerSettings)); - Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(userPasswordConfigurationSettings)); - Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(webRoutingSettings)); - } - - protected virtual void ComposeApplication(bool withApplication) - { - ComposeSettings(); - - if (withApplication == false) return; - - // default Datalayer/Repositories/SQL/Database/etc... - Builder.AddRepositories(); - - Builder.Services.AddUnique(); - - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - - // register filesystems - Builder.Services.AddUnique(factory => TestObjects.GetFileSystemsMock()); - - - var scheme = Mock.Of(); - - var mediaFileManager = new MediaFileManager(Mock.Of(), scheme, Mock.Of>(), Mock.Of()); - Builder.Services.AddUnique(factory => mediaFileManager); - - // no factory (noop) - Builder.Services.AddUnique(); - - // register application stuff (database factory & context, services...) - Builder.WithCollectionBuilder() - .AddCoreMappers(); - - Builder.Services.AddUnique(_ => new TransientEventMessagesFactory()); - - var globalSettings = Microsoft.Extensions.Options.Options.Create(new GlobalSettings()); - var connectionStrings = Microsoft.Extensions.Options.Options.Create(new ConnectionStrings()); - - Builder.Services.AddUnique(f => new UmbracoDatabaseFactory(_loggerFactory.CreateLogger(), - LoggerFactory, - globalSettings, - connectionStrings, - new Lazy(f.GetRequiredService), - TestHelper.DbProviderFactoryCreator, - new DatabaseSchemaCreatorFactory(LoggerFactory.CreateLogger(), LoggerFactory, UmbracoVersion, Mock.Of()))); - - Builder.Services.AddUnique(f => f.GetService().SqlContext); - - Builder.WithCollectionBuilder(); // empty - - Builder.Services.AddUnique(factory - => TestObjects.GetScopeProvider(_loggerFactory, factory.GetService(), factory.GetService())); - Builder.Services.AddUnique(factory => (IScopeAccessor)factory.GetRequiredService()); - - Builder.AddServices(); - - // composition root is doing weird things, fix - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - - // somehow property editor ends up wanting this - Builder.WithCollectionBuilder(); - - Builder.Services.AddUnique(); - - // note - don't register collections, use builders - Builder.WithCollectionBuilder(); - Builder.Services.AddUnique(); - Builder.Services.AddUnique(); - - - Builder.Services.AddUnique(TestHelper.GetHttpContextAccessor(GetHttpContextFactory("/").HttpContext)); - } - - #endregion - - protected FakeHttpContextFactory GetHttpContextFactory(string url, RouteData routeData = null) - { - var factory = routeData != null - ? new FakeHttpContextFactory(url, routeData) - : new FakeHttpContextFactory(url); - - return factory; - } - - #region Initialize - - protected virtual void InitializeApplication(bool withApplication) - { - if (withApplication == false) return; - - TestHelper.InitializeContentDirectories(); - } - - #endregion - - #region TearDown and Reset - - [TearDown] - public virtual void TearDown() - { - FirstTestInFixture = false; - FirstTestInSession = false; - - Reset(); - - if (Options.WithApplication) - { - TestHelper.CleanContentDirectories(); - TestHelper.CleanUmbracoSettingsConfig(); - } - } - - protected virtual void Reset() - { - try - { - // reset and dispose scopes - // ensures we don't leak an opened database connection - // which would lock eg SqlCe .sdf files - if (Factory?.GetService() is ScopeProvider scopeProvider) - { - Scope scope; - while ((scope = scopeProvider.AmbientScope) != null) - { - scope.Reset(); - scope.Dispose(); - } - } - } - catch (ObjectDisposedException ex) - { - if (!ex.ObjectName.Equals(nameof(IServiceProvider))) - throw; - } - - // reset all other static things that should not be static ;( - UriUtility.ResetAppDomainAppVirtualPath(HostingEnvironment); - } - - #endregion - } -} diff --git a/tests/Umbraco.Tests/Umbraco.Tests.csproj b/tests/Umbraco.Tests/Umbraco.Tests.csproj index 75f2e0a805b5..a83c0d64538a 100644 --- a/tests/Umbraco.Tests/Umbraco.Tests.csproj +++ b/tests/Umbraco.Tests/Umbraco.Tests.csproj @@ -135,170 +135,12 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -338,47 +180,10 @@ Umbraco.Web - - - ResXFileCodeGenerator - SqlResources.Designer.cs - Designer - - - ResXFileCodeGenerator - ImportResources.Designer.cs - Designer - - - ResXFileCodeGenerator - TestFiles.Designer.cs - Designer - - - - - Designer - Always - - - Always - - - - - - Designer - - - - - - - - + $(NuGetPackageFolders.Split(';')[0]) diff --git a/tests/Umbraco.Tests/Web/HttpCookieExtensionsTests.cs b/tests/Umbraco.Tests/Web/HttpCookieExtensionsTests.cs deleted file mode 100644 index 3964017e5709..000000000000 --- a/tests/Umbraco.Tests/Web/HttpCookieExtensionsTests.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text; -using System.Threading.Tasks; -using NUnit.Framework; -using Umbraco.Web; - -namespace Umbraco.Tests.Web -{ - [TestFixture] - public class HttpCookieExtensionsTests - { - [TestCase("hello=world;cookies=are fun;", "hello", "world", true)] - [TestCase("HELlo=world;cookies=are fun", "hello", "world", true)] - [TestCase("HELlo= world;cookies=are fun", "hello", "world", true)] - [TestCase("HELlo =world;cookies=are fun", "hello", "world", true)] - [TestCase("hello = world;cookies=are fun;", "hello", "world", true)] - [TestCase("hellos=world;cookies=are fun", "hello", "world", false)] - [TestCase("hello=world;cookies?=are fun?", "hello", "world", true)] - [TestCase("hel?lo=world;cookies=are fun?", "hel?lo", "world", true)] - public void Get_Cookie_Value_From_HttpRequestHeaders(string cookieHeaderVal, string cookieName, string cookieVal, bool matches) - { - var request = new HttpRequestMessage(HttpMethod.Get, "http://test.com"); - var requestHeaders = request.Headers; - requestHeaders.Add("Cookie", cookieHeaderVal); - - var valueFromHeader = requestHeaders.GetCookieValue(cookieName); - - if (matches) - { - Assert.IsNotNull(valueFromHeader); - Assert.AreEqual(cookieVal, valueFromHeader); - } - else - { - Assert.IsNull(valueFromHeader); - } - } - } -} diff --git a/tests/Umbraco.Tests/Web/Mvc/ViewDataDictionaryExtensionTests.cs b/tests/Umbraco.Tests/Web/Mvc/ViewDataDictionaryExtensionTests.cs deleted file mode 100644 index 869fd1b329e0..000000000000 --- a/tests/Umbraco.Tests/Web/Mvc/ViewDataDictionaryExtensionTests.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Web.Mvc; -using NUnit.Framework; -using Umbraco.Web.Mvc; - -namespace Umbraco.Tests.Web.Mvc -{ - [TestFixture] - public class ViewDataDictionaryExtensionTests - { - [Test] - public void Merge_View_Data() - { - var source = new ViewDataDictionary(); - var dest = new ViewDataDictionary(); - source.Add("Test1", "Test1"); - dest.Add("Test2", "Test2"); - - dest.MergeViewDataFrom(source); - - Assert.AreEqual(2, dest.Count); - } - - [Test] - public void Merge_View_Data_Retains_Destination_Values() - { - var source = new ViewDataDictionary(); - var dest = new ViewDataDictionary(); - source.Add("Test1", "Test1"); - dest.Add("Test1", "MyValue"); - dest.Add("Test2", "Test2"); - - dest.MergeViewDataFrom(source); - - Assert.AreEqual(2, dest.Count); - Assert.AreEqual("MyValue", dest["Test1"]); - Assert.AreEqual("Test2", dest["Test2"]); - } - - } -} diff --git a/tests/Umbraco.Tests/masterpages/site1/template2.master b/tests/Umbraco.Tests/masterpages/site1/template2.master deleted file mode 100644 index f1a6da0d512b..000000000000 --- a/tests/Umbraco.Tests/masterpages/site1/template2.master +++ /dev/null @@ -1,5 +0,0 @@ -<%@ Master Language="C#" MasterPageFile="~/umbraco/masterpages/default.master" AutoEventWireup="true" %> - - - -